Merge tag 'upstream/0.6.0' into debian

This commit is contained in:
Didier Raboud
2015-03-03 08:53:35 +01:00
37 changed files with 10988 additions and 534 deletions
+19
View File
@@ -1,6 +1,25 @@
This file lists notable changes in each release. For the full history of all This file lists notable changes in each release. For the full history of all
changes, see ChangeLog. changes, see ChangeLog.
2015-02-03: v0.6.0 release
* Drivers:
- Reduce duplication between AES3500 and AES4000 drivers and
add support for AES3500 device
- Add support for UPEK 147e:2020 and Upek Eikon 2 devices
- Add EgisTec ES603 driver
- Add VFS5011 driver
- Always perform 5 scans for image enrollment
- Better verification with AES1660 driver
- Better verification for a number of AES drivers
* Library:
- Always use Pixman for image manipulation, gdk-pixbuf and ImageMagick
are not supported any more.
* Udev rules:
- Fix warning when USB hub or system does not support power management
2013-08-11: v0.5.1 release 2013-08-11: v0.5.1 release
* Drivers * Drivers
+65 -20
View File
@@ -1,5 +1,5 @@
AC_INIT([libfprint], [0.5.1]) AC_INIT([libfprint], [0.6.0])
AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz check-news]) AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz check-news subdir-objects])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([libfprint/core.c]) AC_CONFIG_SRCDIR([libfprint/core.c])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
@@ -23,11 +23,12 @@ AC_SUBST(lt_major)
AC_SUBST(lt_revision) AC_SUBST(lt_revision)
AC_SUBST(lt_age) AC_SUBST(lt_age)
all_drivers="upeke2 upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes1660 aes2501 aes2550 aes2660 aes4000 vfs101 vfs301" all_drivers="upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes1660 aes2501 aes2550 aes2660 aes3500 aes4000 vfs101 vfs301 vfs5011 upektc_img etes603"
require_imaging='no' require_imaging='no'
require_aeslib='no' require_aeslib='no'
require_aesX660='no' require_aesX660='no'
require_aes3k='no'
enable_upeke2='no' enable_upeke2='no'
enable_upekts='no' enable_upekts='no'
enable_upektc='no' enable_upektc='no'
@@ -40,9 +41,13 @@ enable_aes1660='no'
enable_aes2501='no' enable_aes2501='no'
enable_aes2550='no' enable_aes2550='no'
enable_aes2660='no' enable_aes2660='no'
enable_aes3500='no'
enable_aes4000='no' enable_aes4000='no'
enable_vfs101='no' enable_vfs101='no'
enable_vfs301='no' enable_vfs301='no'
enable_vfs5011='no'
enable_upektc_img='no'
enable_etes603='no'
AC_ARG_WITH([drivers],[AS_HELP_STRING([--with-drivers], AC_ARG_WITH([drivers],[AS_HELP_STRING([--with-drivers],
[List of drivers to enable])], [List of drivers to enable])],
@@ -111,10 +116,18 @@ for driver in `echo ${drivers} | sed -e 's/,/ /g' -e 's/,$//g'`; do
require_aesX660="yes" require_aesX660="yes"
enable_aes2660="yes" enable_aes2660="yes"
;; ;;
aes3500)
AC_DEFINE([ENABLE_AES3500], [], [Build AuthenTec AES3500 driver])
require_aeslib="yes"
require_imaging="yes"
require_aes3k="yes"
enable_aes3500="yes"
;;
aes4000) aes4000)
AC_DEFINE([ENABLE_AES4000], [], [Build AuthenTec AES4000 driver]) AC_DEFINE([ENABLE_AES4000], [], [Build AuthenTec AES4000 driver])
require_aeslib="yes" require_aeslib="yes"
require_imaging="yes" require_imaging="yes"
require_aes3k="yes"
enable_aes4000="yes" enable_aes4000="yes"
;; ;;
vfs101) vfs101)
@@ -125,6 +138,18 @@ for driver in `echo ${drivers} | sed -e 's/,/ /g' -e 's/,$//g'`; do
AC_DEFINE([ENABLE_VFS301], [], [Build Validity VFS301/VFS300 driver]) AC_DEFINE([ENABLE_VFS301], [], [Build Validity VFS301/VFS300 driver])
enable_vfs301="yes" enable_vfs301="yes"
;; ;;
vfs5011)
AC_DEFINE([ENABLE_VFS5011], [], [Build Validity VFS5011 driver])
enable_vfs5011="yes"
;;
upektc_img)
AC_DEFINE([ENABLE_UPEKTC_IMG], [], [Build Upek TouchChip Fingerprint Coprocessor driver])
enable_upektc_img="yes"
;;
etes603)
AC_DEFINE([ENABLE_ETES603], [], [Build EgisTec ES603 driver])
enable_etes603="yes"
;;
esac esac
done done
@@ -140,11 +165,16 @@ AM_CONDITIONAL([ENABLE_AES1660], [test "$enable_aes1660" = "yes"])
AM_CONDITIONAL([ENABLE_AES2501], [test "$enable_aes2501" = "yes"]) AM_CONDITIONAL([ENABLE_AES2501], [test "$enable_aes2501" = "yes"])
AM_CONDITIONAL([ENABLE_AES2550], [test "$enable_aes2550" = "yes"]) AM_CONDITIONAL([ENABLE_AES2550], [test "$enable_aes2550" = "yes"])
AM_CONDITIONAL([ENABLE_AES2660], [test "$enable_aes2660" = "yes"]) AM_CONDITIONAL([ENABLE_AES2660], [test "$enable_aes2660" = "yes"])
AM_CONDITIONAL([ENABLE_AES3500], [test "$enable_aes3500" = "yes"])
AM_CONDITIONAL([ENABLE_AES4000], [test "$enable_aes4000" = "yes"]) AM_CONDITIONAL([ENABLE_AES4000], [test "$enable_aes4000" = "yes"])
AM_CONDITIONAL([REQUIRE_AESLIB], [test "$require_aeslib" = "yes"]) AM_CONDITIONAL([REQUIRE_AESLIB], [test "$require_aeslib" = "yes"])
AM_CONDITIONAL([REQUIRE_AESX660], [test "$require_aesX660" = "yes"]) AM_CONDITIONAL([REQUIRE_AESX660], [test "$require_aesX660" = "yes"])
AM_CONDITIONAL([REQUIRE_AES3K], [test "$require_aes3k" = "yes"])
AM_CONDITIONAL([ENABLE_VFS101], [test "$enable_vfs101" = "yes"]) AM_CONDITIONAL([ENABLE_VFS101], [test "$enable_vfs101" = "yes"])
AM_CONDITIONAL([ENABLE_VFS301], [test "$enable_vfs301" = "yes"]) AM_CONDITIONAL([ENABLE_VFS301], [test "$enable_vfs301" = "yes"])
AM_CONDITIONAL([ENABLE_VFS5011], [test "$enable_vfs5011" = "yes"])
AM_CONDITIONAL([ENABLE_UPEKTC_IMG], [test "$enable_upektc_img" = "yes"])
AM_CONDITIONAL([ENABLE_ETES603], [test "$enable_etes603" = "yes"])
PKG_CHECK_MODULES(LIBUSB, [libusb-1.0 >= 0.9.1]) PKG_CHECK_MODULES(LIBUSB, [libusb-1.0 >= 0.9.1])
@@ -160,8 +190,7 @@ PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.28])
AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS) AC_SUBST(GLIB_LIBS)
imagemagick_found=no pixman_found=no
gdkpixbuf_found=no
AC_ARG_ENABLE(udev-rules, AC_ARG_ENABLE(udev-rules,
AC_HELP_STRING([--enable-udev-rules],[Update the udev rules]), AC_HELP_STRING([--enable-udev-rules],[Update the udev rules]),
@@ -189,20 +218,13 @@ AC_MSG_NOTICE([installing udev rules in ${ac_with_udev_rules_dir}])
AC_SUBST([udev_rulesdir],[${ac_with_udev_rules_dir}]) AC_SUBST([udev_rulesdir],[${ac_with_udev_rules_dir}])
if test "$require_imaging" = "yes"; then if test "$require_imaging" = "yes"; then
PKG_CHECK_MODULES(IMAGING, gthread-2.0 gdk-pixbuf-2.0, [gdkpixbuf_found=yes], [gdkpixbuf_found=no]) PKG_CHECK_MODULES(IMAGING, pixman-1, [pixman_found=yes], [pixman_found=no])
if test "$gdkpixbuf_found" != "yes"; then if test "$pixman_found" != "yes"; then
PKG_CHECK_MODULES(IMAGING, ImageMagick, [imagemagick_found=yes], [imagemagick_found=no]) AC_MSG_ERROR([pixman is required for imaging support])
fi fi
fi fi
if test "$require_imaging" = "yes"; then AM_CONDITIONAL([REQUIRE_PIXMAN], [test "$pixman_found" = "yes"])
if test "$gdkpixbuf_found" != "yes" && test "$imagemagick_found" != "yes"; then
AC_MSG_ERROR([gdk-pixbuf or ImageMagick is required for imaging support])
fi
fi
AM_CONDITIONAL([REQUIRE_GDKPIXBUF], [test "$gdkpixbuf_found" = "yes"])
AM_CONDITIONAL([REQUIRE_IMAGEMAGICK], [test "$imagemagick_found" = "yes"])
AC_SUBST(IMAGING_CFLAGS) AC_SUBST(IMAGING_CFLAGS)
AC_SUBST(IMAGING_LIBS) AC_SUBST(IMAGING_LIBS)
@@ -272,10 +294,8 @@ AM_CFLAGS="-std=gnu99 $inline_cflags -Wall -Wundef -Wunused -Wstrict-prototypes
AC_SUBST(AM_CFLAGS) AC_SUBST(AM_CFLAGS)
if test "$require_imaging" = "yes"; then if test "$require_imaging" = "yes"; then
if test x$gdkpixbuf_found != no; then if test x$pixman_found != no; then
AC_MSG_NOTICE([** Using gdk-pixbuf for imaging]) AC_MSG_NOTICE([** Using pixman for imaging])
else
AC_MSG_NOTICE([** Using ImageMagick for imaging])
fi fi
else else
AC_MSG_NOTICE([ Imaging support disabled]) AC_MSG_NOTICE([ Imaging support disabled])
@@ -341,6 +361,11 @@ if test x$enable_aes2660 != xno ; then
else else
AC_MSG_NOTICE([ aes2660 driver disabled]) AC_MSG_NOTICE([ aes2660 driver disabled])
fi fi
if test x$enable_aes3500 != xno ; then
AC_MSG_NOTICE([** aes3500 driver enabled])
else
AC_MSG_NOTICE([ aes3500 driver disabled])
fi
if test x$enable_aes4000 != xno ; then if test x$enable_aes4000 != xno ; then
AC_MSG_NOTICE([** aes4000 driver enabled]) AC_MSG_NOTICE([** aes4000 driver enabled])
else else
@@ -356,6 +381,21 @@ if test x$enable_vfs301 != xno ; then
else else
AC_MSG_NOTICE([ vfs301 driver disabled]) AC_MSG_NOTICE([ vfs301 driver disabled])
fi fi
if test x$enable_vfs5011 != xno ; then
AC_MSG_NOTICE([** vfs5011 driver enabled])
else
AC_MSG_NOTICE([ vfs5011 driver disabled])
fi
if test x$enable_upektc_img != xno ; then
AC_MSG_NOTICE([** upektc_img driver enabled])
else
AC_MSG_NOTICE([ upektc_img driver disabled])
fi
if test x$enable_etes603 != xno ; then
AC_MSG_NOTICE([** etes603 driver enabled])
else
AC_MSG_NOTICE([ etes603 driver disabled])
fi
if test x$require_aeslib != xno ; then if test x$require_aeslib != xno ; then
AC_MSG_NOTICE([** aeslib helper functions enabled]) AC_MSG_NOTICE([** aeslib helper functions enabled])
else else
@@ -366,6 +406,11 @@ if test x$require_aesX660 != xno ; then
else else
AC_MSG_NOTICE([ aesX660 common routines disabled]) AC_MSG_NOTICE([ aesX660 common routines disabled])
fi fi
if test x$require_aes3k != xno ; then
AC_MSG_NOTICE([** aes3k common routines enabled])
else
AC_MSG_NOTICE([ aes3k common routines disabled])
fi
AC_CONFIG_FILES([libfprint.pc] [Makefile] [libfprint/Makefile] [examples/Makefile] [doc/Makefile]) AC_CONFIG_FILES([libfprint.pc] [Makefile] [libfprint/Makefile] [examples/Makefile] [doc/Makefile])
AC_OUTPUT AC_OUTPUT
+32 -9
View File
@@ -12,11 +12,15 @@ AES1660_SRC = drivers/aes1660.c drivers/aes1660.h
AES2501_SRC = drivers/aes2501.c drivers/aes2501.h AES2501_SRC = drivers/aes2501.c drivers/aes2501.h
AES2550_SRC = drivers/aes2550.c drivers/aes2550.h AES2550_SRC = drivers/aes2550.c drivers/aes2550.h
AES2660_SRC = drivers/aes2660.c drivers/aes2660.h AES2660_SRC = drivers/aes2660.c drivers/aes2660.h
AES3500_SRC = drivers/aes3500.c
AES4000_SRC = drivers/aes4000.c AES4000_SRC = drivers/aes4000.c
FDU2000_SRC = drivers/fdu2000.c FDU2000_SRC = drivers/fdu2000.c
VCOM5S_SRC = drivers/vcom5s.c VCOM5S_SRC = drivers/vcom5s.c
VFS101_SRC = drivers/vfs101.c VFS101_SRC = drivers/vfs101.c
VFS301_SRC = drivers/vfs301.c drivers/vfs301_proto.c drivers/vfs301_proto.h drivers/vfs301_proto_fragments.h VFS301_SRC = drivers/vfs301.c drivers/vfs301_proto.c drivers/vfs301_proto.h drivers/vfs301_proto_fragments.h
VFS5011_SRC = drivers/vfs5011.c drivers/vfs5011_proto.h
UPEKTC_IMG_SRC = drivers/upektc_img.c drivers/upektc_img.h
ETES603_SRC = drivers/etes603.c
EXTRA_DIST = \ EXTRA_DIST = \
$(UPEKE2_SRC) \ $(UPEKE2_SRC) \
@@ -29,17 +33,22 @@ EXTRA_DIST = \
$(AES2501_SRC) \ $(AES2501_SRC) \
$(AES2550_SRC) \ $(AES2550_SRC) \
$(AES2660_SRC) \ $(AES2660_SRC) \
$(AES3500_SRC) \
$(AES4000_SRC) \ $(AES4000_SRC) \
$(FDU2000_SRC) \ $(FDU2000_SRC) \
$(VCOM5S_SRC) \ $(VCOM5S_SRC) \
$(VFS101_SRC) \ $(VFS101_SRC) \
$(VFS301_SRC) \ $(VFS301_SRC) \
$(VFS5011_SRC) \
$(UPEKTC_IMG_SRC) \
$(ETES603_SRC) \
drivers/aesx660.c \ drivers/aesx660.c \
drivers/aesx660.h \ drivers/aesx660.h \
drivers/aes3k.c \
drivers/aes3k.h \
drivers/driver_ids.h \ drivers/driver_ids.h \
aeslib.c aeslib.h \ aeslib.c aeslib.h \
imagemagick.c \ pixman.c \
gdkpixbuf.c \
60-fprint-autosuspend.rules 60-fprint-autosuspend.rules
DRIVER_SRC = DRIVER_SRC =
@@ -87,7 +96,7 @@ libfprint_la_LDFLAGS = -version-info @lt_major@:@lt_revision@:@lt_age@
libfprint_la_LIBADD = -lm $(LIBUSB_LIBS) $(GLIB_LIBS) $(CRYPTO_LIBS) libfprint_la_LIBADD = -lm $(LIBUSB_LIBS) $(GLIB_LIBS) $(CRYPTO_LIBS)
fprint_list_udev_rules_SOURCES = fprint-list-udev-rules.c fprint_list_udev_rules_SOURCES = fprint-list-udev-rules.c
fprint_list_udev_rules_CFLAGS = -fvisibility=hidden -I$(srcdir)/nbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(IMAGEMAGICK_CFLAGS) $(CRYPTO_CFLAGS) $(AM_CFLAGS) fprint_list_udev_rules_CFLAGS = -fvisibility=hidden -I$(srcdir)/nbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(CRYPTO_CFLAGS) $(AM_CFLAGS)
fprint_list_udev_rules_LDADD = $(builddir)/libfprint.la $(GLIB_LIBS) fprint_list_udev_rules_LDADD = $(builddir)/libfprint.la $(GLIB_LIBS)
udev_rules_DATA = 60-fprint-autosuspend.rules udev_rules_DATA = 60-fprint-autosuspend.rules
@@ -145,6 +154,10 @@ if ENABLE_AES2660
DRIVER_SRC += $(AES2660_SRC) DRIVER_SRC += $(AES2660_SRC)
endif endif
if ENABLE_AES3500
DRIVER_SRC += $(AES3500_SRC)
endif
if ENABLE_AES4000 if ENABLE_AES4000
DRIVER_SRC += $(AES4000_SRC) DRIVER_SRC += $(AES4000_SRC)
endif endif
@@ -157,14 +170,20 @@ if ENABLE_VFS301
DRIVER_SRC += $(VFS301_SRC) DRIVER_SRC += $(VFS301_SRC)
endif endif
if REQUIRE_IMAGEMAGICK if ENABLE_VFS5011
OTHER_SRC += imagemagick.c DRIVER_SRC += $(VFS5011_SRC)
libfprint_la_CFLAGS += $(IMAGING_CFLAGS)
libfprint_la_LIBADD += $(IMAGING_LIBS)
endif endif
if REQUIRE_GDKPIXBUF if ENABLE_UPEKTC_IMG
OTHER_SRC += gdkpixbuf.c DRIVER_SRC += $(UPEKTC_IMG_SRC)
endif
if ENABLE_ETES603
DRIVER_SRC += $(ETES603_SRC)
endif
if REQUIRE_PIXMAN
OTHER_SRC += pixman.c
libfprint_la_CFLAGS += $(IMAGING_CFLAGS) libfprint_la_CFLAGS += $(IMAGING_CFLAGS)
libfprint_la_LIBADD += $(IMAGING_LIBS) libfprint_la_LIBADD += $(IMAGING_LIBS)
endif endif
@@ -177,6 +196,10 @@ if REQUIRE_AESX660
OTHER_SRC += drivers/aesx660.c drivers/aesx660.h OTHER_SRC += drivers/aesx660.c drivers/aesx660.h
endif endif
if REQUIRE_AES3K
OTHER_SRC += drivers/aes3k.c drivers/aes3k.h
endif
libfprint_la_SOURCES = \ libfprint_la_SOURCES = \
fp_internal.h \ fp_internal.h \
async.c \ async.c \
+234 -93
View File
@@ -158,127 +158,268 @@ void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
continue_write_regv(wdata); continue_write_regv(wdata);
} }
void aes_assemble_image(unsigned char *input, size_t width, size_t height, static inline unsigned char aes_get_pixel(struct aes_stripe *frame,
unsigned char *output) unsigned int x,
unsigned int y,
unsigned int frame_width,
unsigned int frame_height)
{ {
size_t row, column; unsigned char ret;
for (column = 0; column < width; column++) { ret = frame->data[x * (frame_height >> 1) + (y >> 1)];
for (row = 0; row < height; row += 2) { ret = y % 2 ? ret >> 4 : ret & 0xf;
output[width * row + column] = (*input & 0x0f) * 17; ret *= 17;
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
input++; return ret;
}
static unsigned int calc_error(struct aes_stripe *first_frame,
struct aes_stripe *second_frame,
int dx,
int dy,
unsigned int frame_width,
unsigned int frame_height)
{
unsigned int width, height;
unsigned int x1, y1, x2, y2, err, i, j;
width = frame_width - (dx > 0 ? dx : -dx);
height = frame_height - dy;
y1 = 0;
y2 = dy;
i = 0;
err = 0;
do {
x1 = dx < 0 ? 0 : dx;
x2 = dx < 0 ? -dx : 0;
j = 0;
do {
unsigned char v1, v2;
v1 = aes_get_pixel(first_frame, x1, y1, frame_width, frame_height);
v2 = aes_get_pixel(second_frame, x2, y2, frame_width, frame_height);
err += v1 > v2 ? v1 - v2 : v2 - v1;
j++;
x1++;
x2++;
} while (j < width);
i++;
y1++;
y2++;
} while (i < height);
/* Normalize error */
err *= (frame_height * frame_width);
err /= (height * width);
if (err == 0)
return INT_MAX;
return err;
}
/* This function is rather CPU-intensive. It's better to use hardware
* to detect movement direction when possible.
*/
static void find_overlap(struct aes_stripe *first_frame,
struct aes_stripe *second_frame,
unsigned int *min_error,
unsigned int frame_width,
unsigned int frame_height)
{
int dx, dy;
unsigned int err;
*min_error = INT_MAX;
/* Seeking in horizontal and vertical dimensions,
* for horizontal dimension we'll check only 8 pixels
* in both directions. For vertical direction diff is
* rarely less than 2, so start with it.
*/
for (dy = 2; dy < frame_height; dy++) {
for (dx = -8; dx < 8; dx++) {
err = calc_error(first_frame, second_frame,
dx, dy, frame_width, frame_height);
if (err < *min_error) {
*min_error = err;
second_frame->delta_x = -dx;
second_frame->delta_y = dy;
}
} }
} }
} }
/* find overlapping parts of frames */ unsigned int aes_calc_delta(GSList *stripes, size_t num_stripes,
static unsigned int find_overlap(unsigned char *first_frame,
unsigned char *second_frame, unsigned int *min_error,
unsigned int frame_width, unsigned int frame_height)
{
unsigned int dy;
unsigned int not_overlapped_height = 0;
/* 255 is highest brightness value for an 8bpp image */
*min_error = 255 * frame_width * frame_height;
for (dy = 0; dy < frame_height; dy++) {
/* Calculating difference (error) between parts of frames */
unsigned int i;
unsigned int error = 0;
for (i = 0; i < frame_width * (frame_height - dy); i++) {
/* Using ? operator to avoid abs function */
error += first_frame[i] > second_frame[i] ?
(first_frame[i] - second_frame[i]) :
(second_frame[i] - first_frame[i]);
}
/* Normalize error */
error *= 15;
error /= i;
if (error < *min_error) {
*min_error = error;
not_overlapped_height = dy;
}
first_frame += frame_width;
}
return not_overlapped_height;
}
/* assemble a series of frames into a single image */
static unsigned int assemble(GSList *list_entry, size_t num_stripes,
unsigned int frame_width, unsigned int frame_height, unsigned int frame_width, unsigned int frame_height,
unsigned char *output, gboolean reverse, unsigned int *errors_sum) gboolean reverse)
{ {
uint8_t *assembled = output; GSList *list_entry = stripes;
int frame; GTimer *timer;
uint32_t image_height = frame_height; int frame = 1;
unsigned int min_error, frame_size = frame_width * frame_height; int height = 0;
*errors_sum = 0; struct aes_stripe *prev_stripe = list_entry->data;
unsigned int min_error;
if (reverse) list_entry = g_slist_next(list_entry);
output += (num_stripes - 1) * frame_size;
for (frame = 0; frame < num_stripes; frame++) {
aes_assemble_image(list_entry->data, frame_width, frame_height, output);
if (reverse) timer = g_timer_new();
output -= frame_size; do {
struct aes_stripe *cur_stripe = list_entry->data;
if (reverse) {
find_overlap(prev_stripe, cur_stripe, &min_error,
frame_width, frame_height);
prev_stripe->delta_y = -prev_stripe->delta_y;
prev_stripe->delta_x = -prev_stripe->delta_x;
}
else else
output += frame_size; find_overlap(cur_stripe, prev_stripe, &min_error,
frame_width, frame_height);
frame++;
height += prev_stripe->delta_y;
prev_stripe = cur_stripe;
list_entry = g_slist_next(list_entry); list_entry = g_slist_next(list_entry);
} while (frame < num_stripes);
if (height < 0)
height = -height;
height += frame_height;
g_timer_stop(timer);
fp_dbg("calc delta completed in %f secs", g_timer_elapsed(timer, NULL));
g_timer_destroy(timer);
return height;
}
static inline void aes_blit_stripe(struct fp_img *img,
struct aes_stripe *stripe,
int x, int y, unsigned int frame_width,
unsigned int frame_height)
{
unsigned int ix, iy;
unsigned int fx, fy;
unsigned int width, height;
/* Find intersection */
if (x < 0) {
width = frame_width + x;
ix = 0;
fx = -x;
} else {
ix = x;
fx = 0;
width = frame_width;
}
if ((ix + width) > img->width)
width = img->width - ix;
if (y < 0) {
iy = 0;
fy = -y;
height = frame_height + y;
} else {
iy = y;
fy = 0;
height = frame_height;
} }
/* Detecting where frames overlaped */ if (fx > frame_width)
output = assembled; return;
for (frame = 1; frame < num_stripes; frame++) {
int not_overlapped;
output += frame_size; if (fy > frame_height)
not_overlapped = find_overlap(assembled, output, &min_error, return;
frame_width, frame_height);
*errors_sum += min_error; if (ix > img->width)
image_height += not_overlapped; return;
assembled += frame_width * not_overlapped;
memcpy(assembled, output, frame_size); if (iy > img->height)
return;
if ((iy + height) > img->height)
height = img->height - iy;
for (; fy < height; fy++, iy++) {
if (x < 0) {
ix = 0;
fx = -x;
} else {
ix = x;
fx = 0;
}
for (; fx < width; fx++, ix++) {
img->data[ix + (iy * img->width)] = aes_get_pixel(stripe, fx, fy, frame_width, frame_height);
}
} }
return image_height;
} }
struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len, struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len,
unsigned int frame_width, unsigned int frame_height) unsigned int frame_width, unsigned int frame_height, unsigned int img_width)
{ {
size_t final_size; GSList *stripe;
struct fp_img *img; struct fp_img *img;
unsigned int frame_size = frame_width * frame_height; int height = 0;
unsigned int errors_sum, r_errors_sum; int i, y, x;
gboolean reverse = FALSE;
struct aes_stripe *aes_stripe;
BUG_ON(stripes_len == 0); BUG_ON(stripes_len == 0);
BUG_ON(img_width < frame_width);
/* create buffer big enough for max image */ /* Calculate height */
img = fpi_img_new(stripes_len * frame_size); i = 0;
stripe = stripes;
img->flags = FP_IMG_COLORS_INVERTED; /* No offset for 1st image */
img->height = assemble(stripes, stripes_len, aes_stripe = stripe->data;
frame_width, frame_height, aes_stripe->delta_x = 0;
img->data, FALSE, &errors_sum); aes_stripe->delta_y = 0;
img->height = assemble(stripes, stripes_len, do {
frame_width, frame_height, aes_stripe = stripe->data;
img->data, TRUE, &r_errors_sum);
if (r_errors_sum > errors_sum) { height += aes_stripe->delta_y;
img->height = assemble(stripes, stripes_len, i++;
frame_width, frame_height, stripe = g_slist_next(stripe);
img->data, FALSE, &errors_sum); } while (i < stripes_len);
img->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
fp_dbg("normal scan direction"); fp_dbg("height is %d", height);
} else {
fp_dbg("reversed scan direction"); if (height < 0) {
reverse = TRUE;
height = -height;
} }
/* now that overlap has been removed, resize output image buffer */ /* For last frame */
final_size = img->height * frame_width; height += frame_height;
img = fpi_img_resize(img, final_size);
img->width = frame_width; /* Create buffer big enough for max image */
img = fpi_img_new(img_width * height);
img->flags = FP_IMG_COLORS_INVERTED;
img->width = img_width;
img->height = height;
/* Assemble stripes */
i = 0;
stripe = stripes;
y = reverse ? (height - frame_height) : 0;
x = (img_width - frame_width) / 2;
do {
aes_stripe = stripe->data;
y += aes_stripe->delta_y;
x += aes_stripe->delta_x;
aes_blit_stripe(img, aes_stripe, x, y, frame_width, frame_height);
stripe = g_slist_next(stripe);
i++;
} while (i < stripes_len);
return img; return img;
} }
+10 -3
View File
@@ -27,17 +27,24 @@ struct aes_regwrite {
unsigned char value; unsigned char value;
}; };
struct aes_stripe {
int delta_x;
int delta_y;
unsigned char data[0];
};
typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result, typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result,
void *user_data); void *user_data);
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs, 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); unsigned int num_regs, aes_write_regv_cb callback, void *user_data);
void aes_assemble_image(unsigned char *input, size_t width, size_t height, unsigned int aes_calc_delta(GSList *stripes, size_t stripes_len,
unsigned char *output); unsigned int frame_width, unsigned int frame_height,
gboolean reverse);
struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len, struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len,
unsigned int frame_width, unsigned int frame_height); unsigned int frame_width, unsigned int frame_height, unsigned int img_width);
#endif #endif
+98
View File
@@ -412,3 +412,101 @@ void fpi_drvcb_identify_stopped(struct fp_dev *dev)
dev->identify_stop_cb(dev, dev->identify_stop_cb_data); dev->identify_stop_cb(dev, dev->identify_stop_cb_data);
} }
API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
fp_capture_cb callback, void *user_data)
{
struct fp_driver *drv = dev->drv;
int r;
fp_dbg("");
if (!drv->capture_start)
return -ENOTSUP;
dev->state = DEV_STATE_CAPTURE_STARTING;
dev->capture_cb = callback;
dev->capture_cb_data = user_data;
dev->unconditional_capture = unconditional;
r = drv->capture_start(dev);
if (r < 0) {
dev->capture_cb = NULL;
dev->state = DEV_STATE_ERROR;
fp_err("failed to start verification, error %d", r);
}
return r;
}
/* Drivers call this when capture has started */
void fpi_drvcb_capture_started(struct fp_dev *dev, int status)
{
fp_dbg("");
BUG_ON(dev->state != DEV_STATE_CAPTURE_STARTING);
if (status) {
if (status > 0) {
status = -status;
fp_dbg("adjusted to %d", status);
}
dev->state = DEV_STATE_ERROR;
if (dev->capture_cb)
dev->capture_cb(dev, status, NULL, dev->capture_cb_data);
} else {
dev->state = DEV_STATE_CAPTURING;
}
}
/* Drivers call this to report a capture result (which might mark completion) */
void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
struct fp_img *img)
{
fp_dbg("result %d", result);
BUG_ON(dev->state != DEV_STATE_CAPTURING);
if (result < 0 || result == FP_CAPTURE_COMPLETE)
dev->state = DEV_STATE_CAPTURE_DONE;
if (dev->capture_cb)
dev->capture_cb(dev, result, img, dev->capture_cb_data);
else
fp_dbg("ignoring capture result as no callback is subscribed");
}
/* Drivers call this when capture has stopped */
void fpi_drvcb_capture_stopped(struct fp_dev *dev)
{
fp_dbg("");
BUG_ON(dev->state != DEV_STATE_CAPTURE_STOPPING);
dev->state = DEV_STATE_INITIALIZED;
if (dev->capture_stop_cb)
dev->capture_stop_cb(dev, dev->capture_stop_cb_data);
}
API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
fp_capture_stop_cb callback, void *user_data)
{
struct fp_driver *drv = dev->drv;
int r;
fp_dbg("");
BUG_ON(dev->state != DEV_STATE_ERROR
&& dev->state != DEV_STATE_CAPTURING
&& dev->state != DEV_STATE_CAPTURE_DONE);
dev->capture_cb = NULL;
dev->capture_stop_cb = callback;
dev->capture_stop_cb_data = user_data;
dev->state = DEV_STATE_CAPTURE_STOPPING;
if (!drv->capture_start)
return -ENOTSUP;
if (!drv->capture_stop) {
dev->state = DEV_STATE_INITIALIZED;
fpi_drvcb_capture_stopped(dev);
return 0;
}
r = drv->capture_stop(dev);
if (r < 0) {
fp_err("failed to stop verification");
dev->capture_stop_cb = NULL;
}
return r;
}
+13 -33
View File
@@ -349,6 +349,9 @@ static struct fp_driver * const primitive_drivers[] = {
}; };
static struct fp_img_driver * const img_drivers[] = { static struct fp_img_driver * const img_drivers[] = {
#ifdef ENABLE_AES3500
&aes3500_driver,
#endif
#ifdef ENABLE_AES4000 #ifdef ENABLE_AES4000
&aes4000_driver, &aes4000_driver,
#endif #endif
@@ -383,9 +386,18 @@ static struct fp_img_driver * const img_drivers[] = {
#ifdef ENABLE_VFS301 #ifdef ENABLE_VFS301
&vfs301_driver, &vfs301_driver,
#endif #endif
#ifdef ENABLE_VFS5011
&vfs5011_driver,
#endif
#ifdef ENABLE_UPEKTC #ifdef ENABLE_UPEKTC
&upektc_driver, &upektc_driver,
#endif #endif
#ifdef ENABLE_UPEKTC_IMG
&upektc_img_driver,
#endif
#ifdef ENABLE_ETES603
&etes603_driver,
#endif
/*#ifdef ENABLE_FDU2000 /*#ifdef ENABLE_FDU2000
&fdu2000_driver, &fdu2000_driver,
#endif #endif
@@ -801,7 +813,7 @@ static struct fp_img_dev *dev_to_img_dev(struct fp_dev *dev)
*/ */
API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev) API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev)
{ {
return dev->drv->type == DRIVER_IMAGING; return dev->drv->capture_start != NULL;
} }
/** \ingroup dev /** \ingroup dev
@@ -816,38 +828,6 @@ API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
return dev->drv->identify_start != NULL; return dev->drv->identify_start != NULL;
} }
/** \ingroup dev
* Captures an \ref img "image" from a device. The returned image is the raw
* image provided by the device, you may wish to \ref img_std "standardize" it.
*
* If set, the <tt>unconditional</tt> flag indicates that the device should
* capture an image unconditionally, regardless of whether a finger is there
* or not. If unset, this function will block until a finger is detected on
* the sensor.
*
* \param dev the device
* \param unconditional whether to unconditionally capture an image, or to only capture when a finger is detected
* \param image a location to return the captured image. Must be freed with
* fp_img_free() after use.
* \return 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.
* \sa fp_dev_supports_imaging()
*/
API_EXPORTED int fp_dev_img_capture(struct fp_dev *dev, int unconditional,
struct fp_img **image)
{
struct fp_img_dev *imgdev = dev_to_img_dev(dev);
if (!imgdev) {
fp_dbg("image capture on non-imaging device");
return -ENOTSUP;
}
//return fpi_imgdev_capture(imgdev, unconditional, image);
/* FIXME reimplement async */
return -ENOTSUP;
}
/** \ingroup dev /** \ingroup dev
* Gets the expected width of images that will be captured from the device. * Gets the expected width of images that will be captured from the device.
* This function will return -1 for devices that are not * This function will return -1 for devices that are not
+129 -30
View File
@@ -95,21 +95,33 @@ static const char *finger_num_to_str(enum fp_finger finger)
#endif #endif
static struct fp_print_data *print_data_new(uint16_t driver_id, static struct fp_print_data *print_data_new(uint16_t driver_id,
uint32_t devtype, enum fp_print_data_type type, size_t length) uint32_t devtype, enum fp_print_data_type type)
{ {
struct fp_print_data *data = g_malloc0(sizeof(*data) + length); struct fp_print_data *data = g_malloc0(sizeof(*data));
fp_dbg("length=%zd driver=%02x devtype=%04x", length, driver_id, devtype); fp_dbg("driver=%02x devtype=%04x", driver_id, devtype);
data->driver_id = driver_id; data->driver_id = driver_id;
data->devtype = devtype; data->devtype = devtype;
data->type = type; data->type = type;
data->length = length;
return data; return data;
} }
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev, size_t length) void fpi_print_data_item_free(struct fp_print_data_item *item)
{
g_free(item);
}
struct fp_print_data_item *fpi_print_data_item_new(size_t length)
{
struct fp_print_data_item *item = g_malloc(sizeof(*item) + length);
item->length = length;
return item;
}
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev)
{ {
return print_data_new(dev->drv->id, dev->devtype, return print_data_new(dev->drv->id, dev->devtype,
fpi_driver_get_data_type(dev->drv), length); fpi_driver_get_data_type(dev->drv));
} }
/** \ingroup print_data /** \ingroup print_data
@@ -124,27 +136,115 @@ struct fp_print_data *fpi_print_data_new(struct fp_dev *dev, size_t length)
API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data, API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
unsigned char **ret) unsigned char **ret)
{ {
struct fpi_print_data_fp1 *buf; struct fpi_print_data_fp2 *out_data;
size_t buflen; struct fpi_print_data_item_fp2 *out_item;
struct fp_print_data_item *item;
size_t buflen = 0;
GSList *list_item;
unsigned char *buf;
fp_dbg(""); fp_dbg("");
buflen = sizeof(*buf) + data->length; list_item = data->prints;
buf = malloc(buflen); while (list_item) {
if (!buf) item = list_item->data;
return 0; buflen += sizeof(*out_item);
buflen += item->length;
list_item = g_slist_next(list_item);
}
buflen += sizeof(*out_data);
out_data = g_malloc(buflen);
*ret = (unsigned char *) out_data;
buf = out_data->data;
out_data->prefix[0] = 'F';
out_data->prefix[1] = 'P';
out_data->prefix[2] = '2';
out_data->driver_id = GUINT16_TO_LE(data->driver_id);
out_data->devtype = GUINT32_TO_LE(data->devtype);
out_data->data_type = data->type;
list_item = data->prints;
while (list_item) {
item = list_item->data;
out_item = (struct fpi_print_data_item_fp2 *)buf;
out_item->length = GUINT32_TO_LE(item->length);
/* FIXME: fp_print_data_item->data content is not endianess agnostic */
memcpy(out_item->data, item->data, item->length);
buf += sizeof(*out_item);
buf += item->length;
list_item = g_slist_next(list_item);
}
*ret = (unsigned char *) buf;
buf->prefix[0] = 'F';
buf->prefix[1] = 'P';
buf->prefix[2] = '1';
buf->driver_id = GUINT16_TO_LE(data->driver_id);
buf->devtype = GUINT32_TO_LE(data->devtype);
buf->data_type = data->type;
memcpy(buf->data, data->data, data->length);
return buflen; return buflen;
} }
static struct fp_print_data *fpi_print_data_from_fp1_data(unsigned char *buf,
size_t buflen)
{
size_t print_data_len;
struct fp_print_data *data;
struct fp_print_data_item *item;
struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
print_data_len = buflen - sizeof(*raw);
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
GUINT32_FROM_LE(raw->devtype), raw->data_type);
item = fpi_print_data_item_new(print_data_len);
/* FIXME: fp_print_data->data content is not endianess agnostic */
memcpy(item->data, raw->data, print_data_len);
data->prints = g_slist_prepend(data->prints, item);
return data;
}
static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
size_t buflen)
{
size_t total_data_len, item_len;
struct fp_print_data *data;
struct fp_print_data_item *item;
struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
unsigned char *raw_buf;
struct fpi_print_data_item_fp2 *raw_item;
total_data_len = buflen - sizeof(*raw);
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
GUINT32_FROM_LE(raw->devtype), raw->data_type);
raw_buf = raw->data;
while (total_data_len) {
if (total_data_len < sizeof(*raw_item))
break;
total_data_len -= sizeof(*raw_item);
raw_item = (struct fpi_print_data_item_fp2 *)raw_buf;
item_len = GUINT32_FROM_LE(raw_item->length);
fp_dbg("item len %d, total_data_len %d", item_len, total_data_len);
if (total_data_len < item_len) {
fp_err("corrupted fingerprint data");
break;
}
total_data_len -= item_len;
item = fpi_print_data_item_new(item_len);
/* FIXME: fp_print_data->data content is not endianess agnostic */
memcpy(item->data, raw_item->data, item_len);
data->prints = g_slist_prepend(data->prints, item);
raw_buf += sizeof(*raw_item);
raw_buf += item_len;
}
if (g_slist_length(data->prints) == 0) {
fp_print_data_free(data);
data = NULL;
}
return data;
}
/** \ingroup print_data /** \ingroup print_data
* Load a stored print from a data buffer. The contents of said buffer must * Load a stored print from a data buffer. The contents of said buffer must
* be the untouched contents of a buffer previously supplied to you by the * be the untouched contents of a buffer previously supplied to you by the
@@ -157,24 +257,21 @@ API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf, API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
size_t buflen) size_t buflen)
{ {
struct fpi_print_data_fp1 *raw = (struct fpi_print_data_fp1 *) buf; struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
size_t print_data_len;
struct fp_print_data *data;
fp_dbg("buffer size %zd", buflen); fp_dbg("buffer size %zd", buflen);
if (buflen < sizeof(*raw)) if (buflen < sizeof(*raw))
return NULL; return NULL;
if (strncmp(raw->prefix, "FP1", 3) != 0) { if (strncmp(raw->prefix, "FP1", 3) == 0) {
return fpi_print_data_from_fp1_data(buf, buflen);
} else if (strncmp(raw->prefix, "FP2", 3) == 0) {
return fpi_print_data_from_fp2_data(buf, buflen);
} else {
fp_dbg("bad header prefix"); fp_dbg("bad header prefix");
return NULL;
} }
print_data_len = buflen - sizeof(*raw); return NULL;
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
GUINT32_FROM_LE(raw->devtype), raw->data_type, print_data_len);
memcpy(data->data, raw->data, print_data_len);
return data;
} }
static char *get_path_to_storedir(uint16_t driver_id, uint32_t devtype) static char *get_path_to_storedir(uint16_t driver_id, uint32_t devtype)
@@ -405,6 +502,8 @@ API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
*/ */
API_EXPORTED void fp_print_data_free(struct fp_print_data *data) API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
{ {
if (data)
g_slist_free_full(data->prints, (GDestroyNotify)fpi_print_data_item_free);
g_free(data); g_free(data);
} }
+14 -7
View File
@@ -609,13 +609,24 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
/* stop capturing if MAX_FRAMES is reached */ /* stop capturing if MAX_FRAMES is reached */
if (aesdev->blanks_count > 10 || g_slist_length(aesdev->strips) >= MAX_FRAMES) { if (aesdev->blanks_count > 10 || g_slist_length(aesdev->strips) >= MAX_FRAMES) {
struct fp_img *img; struct fp_img *img;
unsigned int height, rev_height;
fp_dbg("sending stop capture.... blanks=%d frames=%d", aesdev->blanks_count, g_slist_length(aesdev->strips)); fp_dbg("sending stop capture.... blanks=%d frames=%d", aesdev->blanks_count, g_slist_length(aesdev->strips));
/* send stop capture bits */ /* send stop capture bits */
aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL); aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL);
aesdev->strips = g_slist_reverse(aesdev->strips); aesdev->strips = g_slist_reverse(aesdev->strips);
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
rev_height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT, TRUE);
fp_dbg("heights: %d rev: %d", height, rev_height);
if (rev_height < height) {
fp_dbg("Reversed direction");
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
}
img = aes_assemble(aesdev->strips, aesdev->strips_len, img = aes_assemble(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT); FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH + FRAME_WIDTH / 2);
g_slist_free_full(aesdev->strips, g_free); g_slist_free_full(aesdev->strips, g_free);
aesdev->strips = NULL; aesdev->strips = NULL;
aesdev->strips_len = 0; aesdev->strips_len = 0;
@@ -829,13 +840,9 @@ struct fp_img_driver aes1610_driver = {
}, },
.flags = 0, .flags = 0,
.img_height = -1, .img_height = -1,
.img_width = 128, .img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
/* temporarily lowered until we sort out image processing code .bz3_threshold = 50,
* binarized scan quality is good, minutiae detection is accurate,
* it's just that we get fewer minutiae than other scanners (less scanning
* area) */
.bz3_threshold = 10,
.open = dev_init, .open = dev_init,
.close = dev_deinit, .close = dev_deinit,
+2 -8
View File
@@ -49,7 +49,6 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev)); dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE); aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE);
aesdev->h_scale_factor = SCALE_FACTOR;
aesdev->init_seqs[0] = aes1660_init_1; aesdev->init_seqs[0] = aes1660_init_1;
aesdev->init_seqs_len[0] = array_n_elements(aes1660_init_1); aesdev->init_seqs_len[0] = array_n_elements(aes1660_init_1);
aesdev->init_seqs[1] = aes1660_init_2; aesdev->init_seqs[1] = aes1660_init_2;
@@ -102,13 +101,8 @@ struct fp_img_driver aes1660_driver = {
}, },
.flags = 0, .flags = 0,
.img_height = -1, .img_height = -1,
.img_width = FRAME_WIDTH * SCALE_FACTOR, .img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
.bz3_threshold = 70,
/* temporarily lowered until we sort out image processing code
* binarized scan quality is good, minutiae detection is accurate,
* it's just that we get fewer minutiae than other scanners (less scanning
* area) */
.bz3_threshold = 25,
.open = dev_init, .open = dev_init,
.close = dev_deinit, .close = dev_deinit,
+18 -4
View File
@@ -481,10 +481,21 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
aesdev->no_finger_cnt++; aesdev->no_finger_cnt++;
if (aesdev->no_finger_cnt == 3) { if (aesdev->no_finger_cnt == 3) {
struct fp_img *img; struct fp_img *img;
unsigned int height, rev_height;
aesdev->strips = g_slist_reverse(aesdev->strips); aesdev->strips = g_slist_reverse(aesdev->strips);
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
rev_height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT, TRUE);
fp_dbg("heights: %d rev: %d", height, rev_height);
if (rev_height < height) {
fp_dbg("Reversed direction");
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
}
img = aes_assemble(aesdev->strips, aesdev->strips_len, img = aes_assemble(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT); FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH + FRAME_WIDTH / 2);
g_slist_free_full(aesdev->strips, g_free); g_slist_free_full(aesdev->strips, g_free);
aesdev->strips = NULL; aesdev->strips = NULL;
aesdev->strips_len = 0; aesdev->strips_len = 0;
@@ -498,10 +509,13 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
} else { } else {
/* obtain next strip */ /* obtain next strip */
/* FIXME: would preallocating strip buffers be a decent optimization? */ /* FIXME: would preallocating strip buffers be a decent optimization? */
stripdata = g_malloc(192 * 8); struct aes_stripe *stripe = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct aes_stripe));
stripe->delta_x = 0;
stripe->delta_y = 0;
stripdata = stripe->data;
memcpy(stripdata, data + 1, 192*8); memcpy(stripdata, data + 1, 192*8);
aesdev->no_finger_cnt = 0; aesdev->no_finger_cnt = 0;
aesdev->strips = g_slist_prepend(aesdev->strips, stripdata); aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
aesdev->strips_len++; aesdev->strips_len++;
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP); fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
@@ -867,7 +881,7 @@ struct fp_img_driver aes2501_driver = {
}, },
.flags = 0, .flags = 0,
.img_height = -1, .img_height = -1,
.img_width = 192, .img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
.open = dev_init, .open = dev_init,
.close = dev_deinit, .close = dev_deinit,
+12 -5
View File
@@ -204,6 +204,7 @@ static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data)
unsigned char *stripdata; unsigned char *stripdata;
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
struct aes2550_dev *aesdev = dev->priv; struct aes2550_dev *aesdev = dev->priv;
struct aes_stripe *stripe;
int len; int len;
if (data[0] != AES2550_EDATA_MAGIC) { if (data[0] != AES2550_EDATA_MAGIC) {
@@ -214,11 +215,16 @@ static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data)
if (len != (AES2550_STRIP_SIZE - 3)) { if (len != (AES2550_STRIP_SIZE - 3)) {
fp_dbg("Bogus frame len: %.4x\n", len); fp_dbg("Bogus frame len: %.4x\n", len);
} }
stripdata = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2); /* 4 bits per pixel */ stripe = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct aes_stripe)); /* 4 bits per pixel */
stripe->delta_x = (int8_t)data[6];
stripe->delta_y = -(int8_t)data[7];
stripdata = stripe->data;
memcpy(stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2); memcpy(stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2);
aesdev->strips = g_slist_prepend(aesdev->strips, stripdata); aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
aesdev->strips_len++; aesdev->strips_len++;
fp_dbg("deltas: %dx%d", stripe->delta_x, stripe->delta_y);
return 0; return 0;
} }
@@ -242,12 +248,13 @@ static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
struct aes2550_dev *aesdev = dev->priv; struct aes2550_dev *aesdev = dev->priv;
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
(transfer->length == transfer->actual_length)) { (transfer->length == transfer->actual_length) &&
aesdev->strips_len) {
struct fp_img *img; struct fp_img *img;
aesdev->strips = g_slist_reverse(aesdev->strips); aesdev->strips = g_slist_reverse(aesdev->strips);
img = aes_assemble(aesdev->strips, aesdev->strips_len, img = aes_assemble(aesdev->strips, aesdev->strips_len,
FRAME_WIDTH, FRAME_HEIGHT); FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH + FRAME_WIDTH / 2);
g_slist_free_full(aesdev->strips, g_free); g_slist_free_full(aesdev->strips, g_free);
aesdev->strips = NULL; aesdev->strips = NULL;
aesdev->strips_len = 0; aesdev->strips_len = 0;
@@ -637,7 +644,7 @@ struct fp_img_driver aes2550_driver = {
}, },
.flags = 0, .flags = 0,
.img_height = -1, .img_height = -1,
.img_width = 192, .img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
.open = dev_init, .open = dev_init,
.close = dev_deinit, .close = dev_deinit,
+1 -2
View File
@@ -49,7 +49,6 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev)); dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE); aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
/* No scaling for AES2660 */ /* No scaling for AES2660 */
aesdev->h_scale_factor = 1;
aesdev->init_seqs[0] = aes2660_init_1; aesdev->init_seqs[0] = aes2660_init_1;
aesdev->init_seqs_len[0] = array_n_elements(aes2660_init_1); aesdev->init_seqs_len[0] = array_n_elements(aes2660_init_1);
aesdev->init_seqs[1] = aes2660_init_2; aesdev->init_seqs[1] = aes2660_init_2;
@@ -103,7 +102,7 @@ struct fp_img_driver aes2660_driver = {
}, },
.flags = 0, .flags = 0,
.img_height = -1, .img_height = -1,
.img_width = FRAME_WIDTH, .img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
.open = dev_init, .open = dev_init,
.close = dev_deinit, .close = dev_deinit,
+188
View File
@@ -0,0 +1,188 @@
/*
* AuthenTec AES3500 driver for libfprint
*
* AES3500 is a press-typed sensor, which captures image in 128x128
* pixels.
*
* Thanks Rafael Toledo for the Windows driver and the help.
*
* This work is derived from Daniel Drake's AES4000 driver.
*
* Copyright (C) 2011-2013 Juvenn Woo <machese@gmail.com>
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#define FP_COMPONENT "aes3500"
#include <errno.h>
#include <glib.h>
#include <libusb.h>
#include <aeslib.h>
#include <fp_internal.h>
#include "aes3k.h"
#include "driver_ids.h"
#define DATA_BUFLEN 0x2089
/* image size = FRAME_WIDTH x FRAME_WIDTH */
#define FRAME_WIDTH 128
#define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
#define ENLARGE_FACTOR 2
static struct aes_regwrite init_reqs[] = {
/* master reset */
{ 0x80, 0x01 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
{ 0x81, 0x00 },
{ 0x80, 0x00 },
{ 0, 0 },
/* scan reset */
{ 0x80, 0x02 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
/* disable register buffering */
{ 0x80, 0x04 },
{ 0, 0 },
{ 0x80, 0x00 },
{ 0, 0 },
{ 0x81, 0x00 },
{ 0, 0 },
/* windows driver reads registers now (81 02) */
{ 0x80, 0x00 },
{ 0x81, 0x00 },
/* set excitation bias current: 2mhz drive ring frequency,
* 4V drive ring voltage, 16.5mA excitation bias */
{ 0x82, 0x04 },
/* continuously sample drive ring for finger detection,
* 62.50ms debounce delay */
{ 0x83, 0x13 },
{ 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */
{ 0x85, 0x3d }, /* set calibration capacitance */
{ 0x86, 0x03 }, /* detect drive voltage */
{ 0x87, 0x01 }, /* set detection frequency to 125khz */
{ 0x88, 0x02 }, /* set column scan period */
{ 0x89, 0x02 }, /* set measure drive */
{ 0x8a, 0x33 }, /* set measure frequency and sense amplifier bias */
{ 0x8b, 0x33 }, /* set matrix pattern */
{ 0x8c, 0x0f }, /* set demodulation phase 1 */
{ 0x8d, 0x04 }, /* set demodulation phase 2 */
{ 0x8e, 0x23 }, /* set sensor gain */
{ 0x8f, 0x07 }, /* set image parameters */
{ 0x90, 0x00 }, /* carrier offset null */
{ 0x91, 0x1c }, /* set A/D reference high */
{ 0x92, 0x08 }, /* set A/D reference low */
{ 0x93, 0x00 }, /* set start row to 0 */
{ 0x94, 0x07 }, /* set end row */
{ 0x95, 0x00 }, /* set start column to 0 */
{ 0x96, 0x1f }, /* set end column */
{ 0x97, 0x04 }, /* data format and thresholds */
{ 0x98, 0x28 }, /* image data control */
{ 0x99, 0x00 }, /* disable general purpose outputs */
{ 0x9a, 0x0b }, /* set initial scan state */
{ 0x9b, 0x00 }, /* clear challenge word bits */
{ 0x9c, 0x00 }, /* clear challenge word bits */
{ 0x9d, 0x09 }, /* set some challenge word bits */
{ 0x9e, 0x53 }, /* clear challenge word bits */
{ 0x9f, 0x6b }, /* set some challenge word bits */
{ 0, 0 },
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
{ 0x81, 0x04 },
{ 0, 0 },
{ 0x81, 0x00 },
};
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
int r;
struct aes3k_dev *aesdev;
r = libusb_claim_interface(dev->udev, 0);
if (r < 0)
fp_err("could not claim interface 0");
aesdev = dev->priv = g_malloc0(sizeof(struct aes3k_dev));
if (!aesdev)
return -ENOMEM;
if (r == 0)
aesdev->data_buflen = DATA_BUFLEN;
aesdev->frame_width = FRAME_WIDTH;
aesdev->frame_size = FRAME_SIZE;
aesdev->frame_number = FRAME_NUMBER;
aesdev->enlarge_factor = ENLARGE_FACTOR;
aesdev->init_reqs = init_reqs;
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
fpi_imgdev_open_complete(dev, 0);
return r;
}
static void dev_deinit(struct fp_img_dev *dev)
{
struct aes3k_dev *aesdev = dev->priv;
g_free(aesdev);
libusb_release_interface(dev->udev, 0);
fpi_imgdev_close_complete(dev);
}
static const struct usb_id id_table[] = {
{ .vendor = 0x08ff, .product = 0x5731 },
{ 0, 0, 0, },
};
struct fp_img_driver aes3500_driver = {
.driver = {
.id = AES3500_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES3500",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,
.img_height = FRAME_WIDTH * ENLARGE_FACTOR,
.img_width = FRAME_WIDTH * ENLARGE_FACTOR,
/* temporarily lowered until image quality improves */
.bz3_threshold = 9,
.open = dev_init,
.close = dev_deinit,
.activate = aes3k_dev_activate,
.deactivate = aes3k_dev_deactivate,
};
+169
View File
@@ -0,0 +1,169 @@
/*
* AuthenTec AES3500/AES4000 common routines
*
* The AES3500 and AES4000 sensors are press-typed, and could capture
* fingerprint images in 128x128 and 96x96 pixels respectively. They
* share a same communication interface: a number of frames are
* transferred and captured, from which a final image could be
* assembled. Each frame has fixed height of 16 pixels.
*
* As the imaging area is a bit small, only a part of finger could be
* captured, the detected minutiae are not so many that the NBIS
* matching works not so good. The verification rate is very low at the
* moment.
*
* This work is derived from Daniel Drake's AES4000 driver.
*
* Copyright (C) 2013 Juvenn Woo <machese@gmail.com>
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#define FP_COMPONENT "aes3k"
#include <errno.h>
#include <glib.h>
#include <libusb.h>
#include <aeslib.h>
#include <fp_internal.h>
#include "aes3k.h"
#define CTRL_TIMEOUT 1000
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
static void do_capture(struct fp_img_dev *dev);
static void aes3k_assemble_image(unsigned char *input, size_t width, size_t height,
unsigned char *output)
{
size_t row, column;
for (column = 0; column < width; column++) {
for (row = 0; row < height; row += 2) {
output[width * row + column] = (*input & 0x0f) * 17;
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
input++;
}
}
}
static void img_cb(struct libusb_transfer *transfer)
{
struct fp_img_dev *dev = transfer->user_data;
struct aes3k_dev *aesdev = dev->priv;
unsigned char *ptr = transfer->buffer;
struct fp_img *tmp;
struct fp_img *img;
int i;
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
goto err;
} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_imgdev_session_error(dev, -EIO);
goto err;
} else if (transfer->length != transfer->actual_length) {
fpi_imgdev_session_error(dev, -EPROTO);
goto err;
}
fpi_imgdev_report_finger_status(dev, TRUE);
tmp = fpi_img_new(aesdev->frame_width * aesdev->frame_width);
tmp->width = aesdev->frame_width;
tmp->height = aesdev->frame_width;
tmp->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
for (i = 0; i < aesdev->frame_number; i++) {
fp_dbg("frame header byte %02x", *ptr);
ptr++;
aes3k_assemble_image(ptr, aesdev->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * aesdev->frame_width * AES3K_FRAME_HEIGHT));
ptr += aesdev->frame_size;
}
/* 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);
fp_img_free(tmp);
fpi_imgdev_image_captured(dev, img);
/* FIXME: rather than assuming finger has gone, we should poll regs until
* it really has, then restart the capture */
fpi_imgdev_report_finger_status(dev, FALSE);
do_capture(dev);
err:
g_free(transfer->buffer);
aesdev->img_trf = NULL;
libusb_free_transfer(transfer);
}
static void do_capture(struct fp_img_dev *dev)
{
struct aes3k_dev *aesdev = dev->priv;
unsigned char *data;
int r;
aesdev->img_trf = libusb_alloc_transfer(0);
if (!aesdev->img_trf) {
fpi_imgdev_session_error(dev, -EIO);
return;
}
data = g_malloc(aesdev->data_buflen);
libusb_fill_bulk_transfer(aesdev->img_trf, dev->udev, EP_IN, data,
aesdev->data_buflen, img_cb, dev, 0);
r = libusb_submit_transfer(aesdev->img_trf);
if (r < 0) {
g_free(data);
libusb_free_transfer(aesdev->img_trf);
aesdev->img_trf = NULL;
fpi_imgdev_session_error(dev, r);
}
}
static void init_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
{
fpi_imgdev_activate_complete(dev, result);
if (result == 0)
do_capture(dev);
}
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
{
struct aes3k_dev *aesdev = dev->priv;
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 = dev->priv;
/* FIXME: should wait for cancellation to complete before returning
* from deactivation, otherwise app may legally exit before we've
* cleaned up */
if (aesdev->img_trf)
libusb_cancel_transfer(aesdev->img_trf);
fpi_imgdev_deactivate_complete(dev);
}
+58
View File
@@ -0,0 +1,58 @@
/*
* AuthenTec AES3500/AES4000 common routines
*
* The AES3500 and AES4000 sensors are press-typed, and could capture
* fingerprint images in 128x128 and 96x96 pixels respectively. They
* share a same communication interface: a number of frames are
* transferred and captured, from which a final image could be
* assembled. Each frame has fixed height of 16 pixels.
*
* As the imaging area is a bit small, only a part of finger could be
* captured, the detected minutiae are not so many that the NBIS
* matching works not so good. The verification rate is very low at the
* moment.
*
* This work is derived from Daniel Drake's AES4000 driver.
*
* Copyright (C) 2013 Juvenn Woo <machese@gmail.com>
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __AES3K_H
#define __AES3K_H
#define AES3K_FRAME_HEIGHT 16
struct aes3k_dev {
struct libusb_transfer *img_trf;
size_t frame_width; /* image size = frame_width x frame_width */
size_t frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */
size_t frame_number; /* number of frames */
size_t enlarge_factor;
size_t data_buflen; /* buffer length of usb bulk transfer */
struct aes_regwrite *init_reqs; /* initial values sent to device */
size_t init_reqs_len;
};
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state);
void aes3k_dev_deactivate(struct fp_img_dev *dev);
#endif
+34 -121
View File
@@ -1,5 +1,12 @@
/* /*
* AuthenTec AES4000 driver for libfprint * AuthenTec AES4000 driver for libfprint
*
* AES4000 is a press-typed sensor, which captures image in 96x96
* pixels.
*
* This work is derived from Daniel Drake's AES4000 driver.
*
* Copyright (C) 2013 Juvenn Woo <machese@gmail.com>
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
@@ -27,24 +34,19 @@
#include <aeslib.h> #include <aeslib.h>
#include <fp_internal.h> #include <fp_internal.h>
#include "aes3k.h"
#include "driver_ids.h" #include "driver_ids.h"
#define CTRL_TIMEOUT 1000 #define DATA_BUFLEN 0x1259
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
#define DATA_BUFLEN 0x1259
#define NR_SUBARRAYS 6
#define SUBARRAY_LEN 768
#define IMG_HEIGHT 96 /* image size = FRAME_WIDTH x FRAME_WIDTH */
#define IMG_WIDTH 96 #define FRAME_WIDTH 96
#define ENLARGE_FACTOR 3 #define FRAME_SIZE (FRAME_WIDTH * AES3K_FRAME_HEIGHT / 2)
#define FRAME_NUMBER (FRAME_WIDTH / AES3K_FRAME_HEIGHT)
#define ENLARGE_FACTOR 3
struct aes4k_dev {
struct libusb_transfer *img_trf;
};
static const struct aes_regwrite init_reqs[] = { static struct aes_regwrite init_reqs[] = {
/* master reset */ /* master reset */
{ 0x80, 0x01 }, { 0x80, 0x01 },
{ 0, 0 }, { 0, 0 },
@@ -119,119 +121,28 @@ static const struct aes_regwrite init_reqs[] = {
{ 0x81, 0x00 }, { 0x81, 0x00 },
}; };
static void do_capture(struct fp_img_dev *dev);
static void img_cb(struct libusb_transfer *transfer)
{
struct fp_img_dev *dev = transfer->user_data;
struct aes4k_dev *aesdev = dev->priv;
unsigned char *ptr = transfer->buffer;
struct fp_img *tmp;
struct fp_img *img;
int i;
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
goto err;
} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fpi_imgdev_session_error(dev, -EIO);
goto err;
} else if (transfer->length != transfer->actual_length) {
fpi_imgdev_session_error(dev, -EPROTO);
goto err;
}
fpi_imgdev_report_finger_status(dev, TRUE);
tmp = fpi_img_new(IMG_WIDTH * IMG_HEIGHT);
tmp->width = IMG_WIDTH;
tmp->height = IMG_HEIGHT;
tmp->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
for (i = 0; i < NR_SUBARRAYS; i++) {
fp_dbg("subarray header byte %02x", *ptr);
ptr++;
aes_assemble_image(ptr, 96, 16, tmp->data + (i * 96 * 16));
ptr += SUBARRAY_LEN;
}
/* FIXME: this is an ugly hack to make the image big enough for NBIS
* to process reliably */
img = fpi_im_resize(tmp, ENLARGE_FACTOR, ENLARGE_FACTOR);
fp_img_free(tmp);
fpi_imgdev_image_captured(dev, img);
/* FIXME: rather than assuming finger has gone, we should poll regs until
* it really has, then restart the capture */
fpi_imgdev_report_finger_status(dev, FALSE);
do_capture(dev);
err:
g_free(transfer->buffer);
aesdev->img_trf = NULL;
libusb_free_transfer(transfer);
}
static void do_capture(struct fp_img_dev *dev)
{
struct aes4k_dev *aesdev = dev->priv;
unsigned char *data;
int r;
aesdev->img_trf = libusb_alloc_transfer(0);
if (!aesdev->img_trf) {
fpi_imgdev_session_error(dev, -EIO);
return;
}
data = g_malloc(DATA_BUFLEN);
libusb_fill_bulk_transfer(aesdev->img_trf, dev->udev, EP_IN, data,
DATA_BUFLEN, img_cb, dev, 0);
r = libusb_submit_transfer(aesdev->img_trf);
if (r < 0) {
g_free(data);
libusb_free_transfer(aesdev->img_trf);
aesdev->img_trf = NULL;
fpi_imgdev_session_error(dev, r);
}
}
static void init_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
{
fpi_imgdev_activate_complete(dev, result);
if (result == 0)
do_capture(dev);
}
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
{
aes_write_regv(dev, init_reqs, G_N_ELEMENTS(init_reqs), init_reqs_cb, NULL);
return 0;
}
static void dev_deactivate(struct fp_img_dev *dev)
{
struct aes4k_dev *aesdev = dev->priv;
/* FIXME: should wait for cancellation to complete before returning
* from deactivation, otherwise app may legally exit before we've
* cleaned up */
if (aesdev->img_trf)
libusb_cancel_transfer(aesdev->img_trf);
fpi_imgdev_deactivate_complete(dev);
}
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{ {
int r; int r;
struct aes3k_dev *aesdev;
r = libusb_claim_interface(dev->udev, 0); r = libusb_claim_interface(dev->udev, 0);
if (r < 0) if (r < 0)
fp_err("could not claim interface 0"); fp_err("could not claim interface 0");
dev->priv = g_malloc0(sizeof(struct aes4k_dev)); aesdev = dev->priv = g_malloc0(sizeof(struct aes3k_dev));
if (!aesdev)
return -ENOMEM;
if (r == 0) if (r == 0)
aesdev->data_buflen = DATA_BUFLEN;
aesdev->frame_width = FRAME_WIDTH;
aesdev->frame_size = FRAME_SIZE;
aesdev->frame_number = FRAME_NUMBER;
aesdev->enlarge_factor = ENLARGE_FACTOR;
aesdev->init_reqs = init_reqs;
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
fpi_imgdev_open_complete(dev, 0); fpi_imgdev_open_complete(dev, 0);
return r; return r;
@@ -239,11 +150,13 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
static void dev_deinit(struct fp_img_dev *dev) static void dev_deinit(struct fp_img_dev *dev)
{ {
g_free(dev->priv); struct aes3k_dev *aesdev = dev->priv;
g_free(aesdev);
libusb_release_interface(dev->udev, 0); libusb_release_interface(dev->udev, 0);
fpi_imgdev_close_complete(dev); fpi_imgdev_close_complete(dev);
} }
static const struct usb_id id_table[] = { static const struct usb_id id_table[] = {
{ .vendor = 0x08ff, .product = 0x5501 }, { .vendor = 0x08ff, .product = 0x5501 },
{ 0, 0, 0, }, { 0, 0, 0, },
@@ -258,15 +171,15 @@ struct fp_img_driver aes4000_driver = {
.scan_type = FP_SCAN_TYPE_PRESS, .scan_type = FP_SCAN_TYPE_PRESS,
}, },
.flags = 0, .flags = 0,
.img_height = IMG_HEIGHT * ENLARGE_FACTOR, .img_height = FRAME_WIDTH * ENLARGE_FACTOR,
.img_width = IMG_WIDTH * ENLARGE_FACTOR, .img_width = FRAME_WIDTH * ENLARGE_FACTOR,
/* temporarily lowered until image quality improves */ /* temporarily lowered until image quality improves */
.bz3_threshold = 9, .bz3_threshold = 9,
.open = dev_init, .open = dev_init,
.close = dev_deinit, .close = dev_deinit,
.activate = dev_activate, .activate = aes3k_dev_activate,
.deactivate = dev_deactivate, .deactivate = aes3k_dev_deactivate,
}; };
+12 -13
View File
@@ -273,19 +273,25 @@ enum capture_states {
/* Returns number of processed bytes */ /* Returns number of processed bytes */
static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data) static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data)
{ {
struct aes_stripe *stripe;
unsigned char *stripdata; unsigned char *stripdata;
struct fp_img_dev *dev = ssm->priv; struct fp_img_dev *dev = ssm->priv;
struct aesX660_dev *aesdev = dev->priv; struct aesX660_dev *aesdev = dev->priv;
stripdata = g_malloc(aesdev->frame_width * FRAME_HEIGHT / 2); /* 4 bits per pixel */ stripe = g_malloc(aesdev->frame_width * FRAME_HEIGHT / 2 + sizeof(struct aes_stripe)); /* 4 bpp */
stripdata = stripe->data;
fp_dbg("Processing frame %.2x %.2x", data[AESX660_IMAGE_OK_OFFSET], fp_dbg("Processing frame %.2x %.2x", data[AESX660_IMAGE_OK_OFFSET],
data[AESX660_LAST_FRAME_OFFSET]); data[AESX660_LAST_FRAME_OFFSET]);
stripe->delta_x = (int8_t)data[AESX660_FRAME_DELTA_X_OFFSET];
stripe->delta_y = -(int8_t)data[AESX660_FRAME_DELTA_Y_OFFSET];
fp_dbg("Offset to previous frame: %d %d", stripe->delta_x, stripe->delta_y);
if (data[AESX660_IMAGE_OK_OFFSET] == AESX660_IMAGE_OK) { if (data[AESX660_IMAGE_OK_OFFSET] == AESX660_IMAGE_OK) {
memcpy(stripdata, data + AESX660_IMAGE_OFFSET, aesdev->frame_width * FRAME_HEIGHT / 2); memcpy(stripdata, data + AESX660_IMAGE_OFFSET, aesdev->frame_width * FRAME_HEIGHT / 2);
aesdev->strips = g_slist_prepend(aesdev->strips, stripdata); aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
aesdev->strips_len++; aesdev->strips_len++;
return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT); return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT);
} else { } else {
@@ -302,22 +308,15 @@ static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer)
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
(transfer->length == transfer->actual_length)) { (transfer->length == transfer->actual_length)) {
struct fp_img *img, *tmp; struct fp_img *img;
aesdev->strips = g_slist_reverse(aesdev->strips); aesdev->strips = g_slist_reverse(aesdev->strips);
tmp = aes_assemble(aesdev->strips, aesdev->strips_len, img = aes_assemble(aesdev->strips, aesdev->strips_len,
aesdev->frame_width, FRAME_HEIGHT); aesdev->frame_width, FRAME_HEIGHT, aesdev->frame_width + aesdev->frame_width / 2);
g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL); g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL);
g_slist_free(aesdev->strips); g_slist_free(aesdev->strips);
aesdev->strips = NULL; aesdev->strips = NULL;
aesdev->strips_len = 0; aesdev->strips_len = 0;
if (aesdev->h_scale_factor > 1) {
img = fpi_im_resize(tmp, aesdev->h_scale_factor, 1);
fp_img_free(tmp);
} else {
img = tmp;
tmp = NULL;
}
fpi_imgdev_image_captured(dev, img); fpi_imgdev_image_captured(dev, img);
fpi_imgdev_report_finger_status(dev, FALSE); fpi_imgdev_report_finger_status(dev, FALSE);
fpi_ssm_mark_completed(ssm); fpi_ssm_mark_completed(ssm);
@@ -355,7 +354,7 @@ static void capture_read_stripe_data_cb(struct libusb_transfer *transfer)
if (aesdev->buffer_size == aesdev->buffer_max) { if (aesdev->buffer_size == aesdev->buffer_max) {
if (aesdev->buffer_max == AESX660_HEADER_SIZE) { if (aesdev->buffer_max == AESX660_HEADER_SIZE) {
aesdev->buffer_max = aesdev->buffer[AESX660_RESPONSE_SIZE_LSB_OFFSET] + aesdev->buffer_max = aesdev->buffer[AESX660_RESPONSE_SIZE_LSB_OFFSET] +
(aesdev->buffer[AESX660_RESPONSE_SIZE_MSB_OFFSEt] << 8) + AESX660_HEADER_SIZE; (aesdev->buffer[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8) + AESX660_HEADER_SIZE;
fp_dbg("Got frame, type %.2x size %.4x", fp_dbg("Got frame, type %.2x size %.4x",
aesdev->buffer[AESX660_RESPONSE_TYPE_OFFSET], aesdev->buffer[AESX660_RESPONSE_TYPE_OFFSET],
aesdev->buffer_max); aesdev->buffer_max);
+4 -1
View File
@@ -23,7 +23,7 @@
#define AESX660_HEADER_SIZE 3 #define AESX660_HEADER_SIZE 3
#define AESX660_RESPONSE_TYPE_OFFSET 0x00 #define AESX660_RESPONSE_TYPE_OFFSET 0x00
#define AESX660_RESPONSE_SIZE_LSB_OFFSET 0x01 #define AESX660_RESPONSE_SIZE_LSB_OFFSET 0x01
#define AESX660_RESPONSE_SIZE_MSB_OFFSEt 0x02 #define AESX660_RESPONSE_SIZE_MSB_OFFSET 0x02
#define AESX660_CALIBRATE_RESPONSE 0x06 #define AESX660_CALIBRATE_RESPONSE 0x06
#define AESX660_FINGER_DET_RESPONSE 0x40 #define AESX660_FINGER_DET_RESPONSE 0x40
@@ -35,6 +35,9 @@
#define AESX660_LAST_FRAME_OFFSET 0x04 #define AESX660_LAST_FRAME_OFFSET 0x04
#define AESX660_LAST_FRAME_BIT 0x01 #define AESX660_LAST_FRAME_BIT 0x01
#define AESX660_FRAME_DELTA_X_OFFSET 16
#define AESX660_FRAME_DELTA_Y_OFFSET 17
#define AESX660_IMAGE_OFFSET 43 #define AESX660_IMAGE_OFFSET 43
#define AESX660_BULK_TRANSFER_SIZE 4096 #define AESX660_BULK_TRANSFER_SIZE 4096
+4
View File
@@ -36,6 +36,10 @@ enum {
UPEKE2_ID = 13, UPEKE2_ID = 13,
AES1660_ID = 14, AES1660_ID = 14,
AES2660_ID = 15, AES2660_ID = 15,
AES3500_ID = 16,
UPEKTC_IMG_ID = 17,
ETES603_ID = 18,
VFS5011_ID = 19,
}; };
#endif #endif
File diff suppressed because it is too large Load Diff
+8 -9
View File
@@ -48,7 +48,6 @@
enum { enum {
UPEKE2_2016, UPEKE2_2016,
UPEKE2_2020,
}; };
struct upeke2_dev { struct upeke2_dev {
@@ -856,9 +855,6 @@ static int discover(struct libusb_device_descriptor *dsc, uint32_t *devtype)
if (dsc->idProduct == 0x2016 && dsc->bcdDevice == 2) if (dsc->idProduct == 0x2016 && dsc->bcdDevice == 2)
return 1; return 1;
if (dsc->idProduct == 0x2020 && dsc->bcdDevice == 1)
return 1;
return 0; return 0;
} }
@@ -1076,6 +1072,7 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
size_t data_len) size_t data_len)
{ {
struct fp_print_data *fdata = NULL; struct fp_print_data *fdata = NULL;
struct fp_print_data_item *item = NULL;
int result = -EPROTO; int result = -EPROTO;
if (data_len < sizeof(scan_comp)) { if (data_len < sizeof(scan_comp)) {
@@ -1084,9 +1081,11 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
fp_err("unrecognised data prefix %x %x %x %x %x", fp_err("unrecognised data prefix %x %x %x %x %x",
data[0], data[1], data[2], data[3], data[4]); data[0], data[1], data[2], data[3], data[4]);
} else { } else {
fdata = fpi_print_data_new(dev, data_len - sizeof(scan_comp)); fdata = fpi_print_data_new(dev);
memcpy(fdata->data, data + sizeof(scan_comp), item = fpi_print_data_item_new(data_len - sizeof(scan_comp));
memcpy(item->data, data + sizeof(scan_comp),
data_len - sizeof(scan_comp)); data_len - sizeof(scan_comp));
fdata->prints = g_slist_prepend(fdata->prints, item);
result = FP_ENROLL_COMPLETE; result = FP_ENROLL_COMPLETE;
} }
@@ -1248,12 +1247,13 @@ static void verify_start_sm_run_state(struct fpi_ssm *ssm)
break; break;
case VERIFY_INIT: ; case VERIFY_INIT: ;
struct fp_print_data *print = dev->verify_data; struct fp_print_data *print = dev->verify_data;
size_t data_len = sizeof(verify_hdr) + print->length; struct fp_print_data_item *item = print->prints->data;
size_t data_len = sizeof(verify_hdr) + item->length;
unsigned char *data = g_malloc(data_len); unsigned char *data = g_malloc(data_len);
struct libusb_transfer *transfer; struct libusb_transfer *transfer;
memcpy(data, verify_hdr, sizeof(verify_hdr)); memcpy(data, verify_hdr, sizeof(verify_hdr));
memcpy(data + sizeof(verify_hdr), print->data, print->length); memcpy(data + sizeof(verify_hdr), item->data, item->length);
transfer = alloc_send_cmd28_transfer(dev, 0x03, data, data_len, transfer = alloc_send_cmd28_transfer(dev, 0x03, data, data_len,
verify_init_2803_cb, ssm); verify_init_2803_cb, ssm);
g_free(data); g_free(data);
@@ -1461,7 +1461,6 @@ static int verify_stop(struct fp_dev *dev, gboolean iterating)
static const struct usb_id id_table[] = { static const struct usb_id id_table[] = {
{ .vendor = 0x147e, .product = 0x2016, .driver_data = UPEKE2_2016 }, { .vendor = 0x147e, .product = 0x2016, .driver_data = UPEKE2_2016 },
{ .vendor = 0x147e, .product = 0x2020, .driver_data = UPEKE2_2020 },
{ 0, 0, 0, }, /* terminating entry */ { 0, 0, 0, }, /* terminating entry */
}; };
+674
View File
@@ -0,0 +1,674 @@
/*
* UPEK TouchChip driver for libfprint
* Copyright (C) 2013 Vasily Khoruzhick <anarsoul@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "upekts_img"
#include <errno.h>
#include <string.h>
#include <libusb.h>
#include <aeslib.h>
#include <fp_internal.h>
#include "upektc_img.h"
#include "driver_ids.h"
static void start_capture(struct fp_img_dev *dev);
static void start_deactivation(struct fp_img_dev *dev);
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
#define CTRL_TIMEOUT 4000
#define BULK_TIMEOUT 4000
#define IMAGE_WIDTH 144
#define IMAGE_HEIGHT 384
#define IMAGE_SIZE (IMAGE_WIDTH * IMAGE_HEIGHT)
#define MAX_CMD_SIZE 64
#define MAX_RESPONSE_SIZE 2052
#define SHORT_RESPONSE_SIZE 64
struct upekts_img_dev {
unsigned char cmd[MAX_CMD_SIZE];
unsigned char response[MAX_RESPONSE_SIZE];
unsigned char image_bits[IMAGE_SIZE * 2];
unsigned char seq;
size_t image_size;
size_t response_rest;
gboolean deactivating;
};
/****** 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;
byte = cmd_buf[5];
byte &= 0x0f;
byte |= (seq << 4);
cmd_buf[5] = byte;
}
static void upektc_img_cmd_update_crc(unsigned char *cmd_buf, size_t size)
{
/* CRC does not cover Ciao prefix (4 bytes) and CRC location (2 bytes) */
uint16_t crc = udf_crc(cmd_buf + 4, size - 6);
cmd_buf[size - 2] = (crc & 0x00ff);
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)
{
struct fp_img_dev *dev = ssm->priv;
struct upekts_img_dev *upekdev = dev->priv;
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
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, dev->udev, 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);
}
}
static void upektc_img_read_data(struct fpi_ssm *ssm, 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 = ssm->priv;
struct upekts_img_dev *upekdev = dev->priv;
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, dev->udev, 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);
}
}
/****** CAPTURE ******/
enum capture_states {
CAPTURE_INIT_CAPTURE,
CAPTURE_READ_DATA,
CAPTURE_ACK_00_28,
CAPTURE_ACK_08,
CAPTURE_ACK_FRAME,
CAPTURE_NUM_STATES,
};
static void capture_reqs_cb(struct libusb_transfer *transfer)
{
struct 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);
}
}
static int upektc_img_process_image_frame(unsigned char *image_buf, unsigned char *cmd_res)
{
int offset = 8;
int len = ((cmd_res[5] & 0x0f) << 8) | (cmd_res[6]);
len -= 1;
if (cmd_res[7] == 0x2c) {
len -= 10;
offset += 10;
}
if (cmd_res[7] == 0x20) {
len -= 4;
}
memcpy(image_buf, cmd_res + offset, len);
return len;
}
static void capture_read_data_cb(struct libusb_transfer *transfer)
{
struct fpi_ssm *ssm = transfer->user_data;
struct fp_img_dev *dev = ssm->priv;
struct upekts_img_dev *upekdev = dev->priv;
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);
return;
}
if (upekdev->deactivating) {
fp_dbg("Deactivate requested\n");
fpi_ssm_mark_completed(ssm);
return;
}
fp_dbg("request completed, len: %.4x", transfer->actual_length);
if (transfer->actual_length == 0) {
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
return;
}
if (!upekdev->response_rest) {
response_size = ((data[5] & 0x0f) << 8) + data[6];
response_size += 9; /* 7 bytes for header, 2 for CRC */
if (response_size > transfer->actual_length) {
fp_dbg("response_size is %d, actual_length is %d\n",
response_size, transfer->actual_length);
fp_dbg("Waiting for rest of transfer");
BUG_ON(upekdev->response_rest);
upekdev->response_rest = response_size - transfer->actual_length;
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
return;
}
}
upekdev->response_rest = 0;
switch (data[4]) {
case 0x00:
switch (data[7]) {
/* No finger */
case 0x28:
fp_dbg("18th byte is %.2x\n", data[18]);
switch (data[18]) {
case 0x0c:
/* no finger */
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28);
break;
case 0x00:
/* finger is present! */
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28);
break;
default:
/* some error happened, cancel scan */
fp_err("something bad happened, aborting scan :(\n");
fpi_ssm_mark_aborted(ssm, FP_VERIFY_RETRY_REMOVE_FINGER);
break;
}
break;
/* Image frame with additional info */
case 0x2c:
fpi_imgdev_report_finger_status(dev, TRUE);
/* Plain image frame */
case 0x24:
upekdev->image_size +=
upektc_img_process_image_frame(upekdev->image_bits + upekdev->image_size,
data);
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_FRAME);
break;
/* Last image frame */
case 0x20:
upekdev->image_size +=
upektc_img_process_image_frame(upekdev->image_bits + upekdev->image_size,
data);
BUG_ON(upekdev->image_size != IMAGE_SIZE);
fp_dbg("Image size is %d\n", upekdev->image_size);
img = fpi_img_new(IMAGE_SIZE);
memcpy(img->data, upekdev->image_bits, IMAGE_SIZE);
fpi_imgdev_image_captured(dev, img);
fpi_imgdev_report_finger_status(dev, FALSE);
fpi_ssm_mark_completed(ssm);
break;
default:
fp_err("Uknown response!\n");
fpi_ssm_mark_aborted(ssm, -EIO);
break;
}
break;
case 0x08:
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_08);
break;
default:
fp_err("Not handled response!\n");
fpi_ssm_mark_aborted(ssm, -EIO);
}
}
static void capture_run_state(struct fpi_ssm *ssm)
{
struct fp_img_dev *dev = ssm->priv;
struct upekts_img_dev *upekdev = dev->priv;
switch (ssm->cur_state) {
case CAPTURE_INIT_CAPTURE:
upektc_img_submit_req(ssm, upek2020_init_capture, sizeof(upek2020_init_capture),
upekdev->seq, capture_reqs_cb);
upekdev->seq++;
break;
case CAPTURE_READ_DATA:
if (!upekdev->response_rest)
upektc_img_read_data(ssm, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb);
else
upektc_img_read_data(ssm, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE,
SHORT_RESPONSE_SIZE, capture_read_data_cb);
break;
case CAPTURE_ACK_00_28:
upektc_img_submit_req(ssm, 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),
0, capture_reqs_cb);
break;
case CAPTURE_ACK_FRAME:
upektc_img_submit_req(ssm, upek2020_ack_frame, sizeof(upek2020_ack_frame),
upekdev->seq, capture_reqs_cb);
upekdev->seq++;
break;
};
}
static void capture_sm_complete(struct fpi_ssm *ssm)
{
struct fp_img_dev *dev = ssm->priv;
struct upekts_img_dev *upekdev = dev->priv;
int err = ssm->error;
fp_dbg("Capture completed, %d", err);
fpi_ssm_free(ssm);
if (upekdev->deactivating)
start_deactivation(dev);
else if (err)
fpi_imgdev_session_error(dev, err);
else
start_capture(dev);
}
static void start_capture(struct fp_img_dev *dev)
{
struct upekts_img_dev *upekdev = dev->priv;
struct fpi_ssm *ssm;
upekdev->image_size = 0;
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
ssm->priv = dev;
fpi_ssm_start(ssm, capture_sm_complete);
}
/****** INITIALIZATION/DEINITIALIZATION ******/
enum deactivate_states {
DEACTIVATE_DEINIT,
DEACTIVATE_READ_DEINIT_DATA,
DEACTIVATE_NUM_STATES,
};
static void deactivate_reqs_cb(struct libusb_transfer *transfer)
{
struct 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);
}
}
/* TODO: process response properly */
static void deactivate_read_data_cb(struct libusb_transfer *transfer)
{
struct fpi_ssm *ssm = transfer->user_data;
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
fpi_ssm_mark_completed(ssm);
} else {
fpi_ssm_mark_aborted(ssm, -EIO);
}
}
static void deactivate_run_state(struct fpi_ssm *ssm)
{
struct fp_img_dev *dev = ssm->priv;
struct upekts_img_dev *upekdev = dev->priv;
switch (ssm->cur_state) {
case DEACTIVATE_DEINIT:
upektc_img_submit_req(ssm, 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);
break;
};
}
static void deactivate_sm_complete(struct fpi_ssm *ssm)
{
struct fp_img_dev *dev = ssm->priv;
struct upekts_img_dev *upekdev = dev->priv;
int err = ssm->error;
fp_dbg("Deactivate completed");
fpi_ssm_free(ssm);
if (err) {
fpi_imgdev_session_error(dev, err);
return;
}
upekdev->deactivating = FALSE;
fpi_imgdev_deactivate_complete(dev);
}
static void start_deactivation(struct fp_img_dev *dev)
{
struct upekts_img_dev *upekdev = dev->priv;
struct fpi_ssm *ssm;
upekdev->image_size = 0;
ssm = fpi_ssm_new(dev->dev, deactivate_run_state, DEACTIVATE_NUM_STATES);
ssm->priv = dev;
fpi_ssm_start(ssm, deactivate_sm_complete);
}
enum activate_states {
ACTIVATE_CONTROL_REQ_1,
ACTIVATE_READ_CTRL_RESP_1,
ACTIVATE_INIT_1,
ACTIVATE_READ_INIT_1_RESP,
ACTIVATE_INIT_2,
ACTIVATE_READ_INIT_2_RESP,
ACTIVATE_CONTROL_REQ_2,
ACTIVATE_READ_CTRL_RESP_2,
ACTIVATE_INIT_3,
ACTIVATE_READ_INIT_3_RESP,
ACTIVATE_INIT_4,
ACTIVATE_READ_INIT_4_RESP,
ACTIVATE_NUM_STATES,
};
static void init_reqs_ctrl_cb(struct libusb_transfer *transfer)
{
struct fpi_ssm *ssm = transfer->user_data;
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
fpi_ssm_next_state(ssm);
} else {
fpi_ssm_mark_aborted(ssm, -EIO);
}
}
static void init_reqs_cb(struct libusb_transfer *transfer)
{
struct 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);
}
}
/* TODO: process response properly */
static void init_read_data_cb(struct libusb_transfer *transfer)
{
struct fpi_ssm *ssm = transfer->user_data;
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
fpi_ssm_next_state(ssm);
} else {
fpi_ssm_mark_aborted(ssm, -EIO);
}
}
static void activate_run_state(struct fpi_ssm *ssm)
{
struct libusb_transfer *transfer;
struct fp_img_dev *dev = ssm->priv;
struct upekts_img_dev *upekdev = dev->priv;
int r;
switch (ssm->cur_state) {
case ACTIVATE_CONTROL_REQ_1:
case ACTIVATE_CONTROL_REQ_2:
{
unsigned char *data;
transfer = libusb_alloc_transfer(0);
if (!transfer) {
fpi_ssm_mark_aborted(ssm, -ENOMEM);
break;
}
transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER |
LIBUSB_TRANSFER_FREE_TRANSFER;
data = g_malloc0(LIBUSB_CONTROL_SETUP_SIZE + 1);
libusb_fill_control_setup(data,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1);
libusb_fill_control_transfer(transfer, ssm->dev->udev, data,
init_reqs_ctrl_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);
}
}
break;
case ACTIVATE_INIT_1:
upektc_img_submit_req(ssm, 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),
0, init_reqs_cb);
break;
case ACTIVATE_INIT_3:
upektc_img_submit_req(ssm, 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),
upekdev->seq, init_reqs_cb);
/* Seq should be updated after 4th init */
upekdev->seq++;
break;
case ACTIVATE_READ_CTRL_RESP_1:
case ACTIVATE_READ_CTRL_RESP_2:
case ACTIVATE_READ_INIT_1_RESP:
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);
break;
}
}
static void activate_sm_complete(struct fpi_ssm *ssm)
{
struct fp_img_dev *dev = ssm->priv;
int err = ssm->error;
fpi_ssm_free(ssm);
fp_dbg("%s status %d", __func__, err);
fpi_imgdev_activate_complete(dev, err);
if (!err)
start_capture(dev);
}
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
{
struct upekts_img_dev *upekdev = dev->priv;
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
ACTIVATE_NUM_STATES);
ssm->priv = dev;
upekdev->seq = 0;
fpi_ssm_start(ssm, activate_sm_complete);
return 0;
}
static void dev_deactivate(struct fp_img_dev *dev)
{
struct upekts_img_dev *upekdev = dev->priv;
upekdev->deactivating = TRUE;
}
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
/* TODO check that device has endpoints we're using */
int r;
r = libusb_claim_interface(dev->udev, 0);
if (r < 0) {
fp_err("could not claim interface 0");
return r;
}
dev->priv = g_malloc0(sizeof(struct upekts_img_dev));
fpi_imgdev_open_complete(dev, 0);
return 0;
}
static void dev_deinit(struct fp_img_dev *dev)
{
g_free(dev->priv);
libusb_release_interface(dev->udev, 0);
fpi_imgdev_close_complete(dev);
}
static int discover(struct libusb_device_descriptor *dsc, uint32_t *devtype)
{
if (dsc->idProduct == 0x2020 && dsc->bcdDevice == 1)
return 1;
#ifndef ENABLE_UPEKE2
if (dsc->idProduct == 0x2016 && dsc->bcdDevice == 2)
return 1;
#endif
return 0;
}
static const struct usb_id id_table[] = {
#ifndef ENABLE_UPEKE2
{ .vendor = 0x147e, .product = 0x2016 },
#endif
{ .vendor = 0x147e, .product = 0x2020 },
{ 0, 0, 0, },
};
struct fp_img_driver upektc_img_driver = {
.driver = {
.id = UPEKTC_IMG_ID,
.name = FP_COMPONENT,
.full_name = "Upek TouchChip Fingerprint Coprocessor",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
.discover = discover,
},
.flags = 0,
.img_height = IMAGE_HEIGHT,
.img_width = IMAGE_WIDTH,
.bz3_threshold = 70,
.open = dev_init,
.close = dev_deinit,
.activate = dev_activate,
.deactivate = dev_deactivate,
};
+144
View File
@@ -0,0 +1,144 @@
/*
* Upek TouchChip Fingerprint Coprocessor definitions
* Copyright (c) 2013 Vasily Khoruzhick <anarsoul@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __UPEKTC_IMG_H
#define __UPEKTC_IMG_H
static const unsigned char upek2020_init_1[] = {
'C', 'i', 'a', 'o',
0x04,
0x00, 0x0d,
0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x01, 0x00, 0x00, 0x00,
0xda, 0xc1
};
static const unsigned char upek2020_init_2[] = {
0x43, 0x69, 0x61, 0x6f,
0x07,
0x00, 0x01,
0x01,
0x3d, 0x72
};
static const unsigned char upek2020_init_3[] = {
'C', 'i', 'a', 'o',
0x04,
0x00, 0x0d,
0x01, 0x00, 0xbc, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
0x01, 0x00, 0x00, 0x00,
0x55, 0x2f
};
static const unsigned char upek2020_init_4[] = {
'C', 'i', 'a', 'o',
0x00,
0x00, 0x07,
0x28, 0x04, 0x00, 0x00, 0x00, 0x06, 0x04,
0xc0, 0xd6
};
static const unsigned char upek2020_deinit[] = {
'C', 'i', 'a', 'o',
0x07,
0x00, 0x01,
0x01,
0x3d,
0x72
};
static const unsigned char upek2020_init_capture[] = {
'C', 'i', 'a', 'o',
0x00,
0x00, 0x0e, /* Seq = 7, len = 0x00e */
0x28, /* CMD = 0x28 */
0x0b, 0x00, /* Inner len = 0x000b */
0x00, 0x00,
0x0e, /* SUBCMD = 0x0e */
0x02,
0xfe, 0xff, 0xff, 0xff, /* timeout = -2 = 0xfffffffe = infinite time */
0x02,
0x00, /* Wait for acceptable finger */
0x02,
0x14, 0x9a /* CRC */
};
#if 0
static const unsigned char finger_status[] = {
'C', 'i', 'a', 'o',
0x00,
0x70, 0x14, /* Seq = 7, len = 0x014 */
0x28, /* CMD = 0x28 */
0x11, 0x00, /* Inner len = 0x0011 */
0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x26, 0x03, /* CRC */
0x00, 0x00, 0x00, /* Rest is garbage */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif
static const unsigned char upek2020_ack_00_28[] = {
'C', 'i', 'a', 'o',
0x00,
0x80, 0x08, /* Seq = 8, len = 0x008 */
0x28, /* CMD = 0x28 */
0x05, 0x00, /* Inner len = 0x0005 */
0x00, 0x00, 0x00, 0x30, 0x01,
0x6a, 0xc4 /* CRC */
};
#if 0
/* No seq should be tracked here */
static const unsigned char got_finger[] = {
'C', 'i', 'a', 'o',
0x08,
0x00, 0x00, /* Seq = 0, len = 0x000 */
0xa1, 0xa9, /* CRC */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Rest is garbage */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif
/* No seq should be put in there */
static const unsigned char upek2020_ack_08[] = {
'C', 'i', 'a', 'o',
0x09,
0x00, 0x00, /* Seq = 0, len = 0x0 */
0x91, 0x9e /* CRC */
};
static const unsigned char upek2020_ack_frame[] = {
'C', 'i', 'a', 'o',
0x00,
0x50, 0x01, /* Seq = 5, len = 0x001 */
0x30,
0xac, 0x5b /* CRC */
};
#endif
+8 -4
View File
@@ -1077,6 +1077,7 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
size_t data_len) size_t data_len)
{ {
struct fp_print_data *fdata = NULL; struct fp_print_data *fdata = NULL;
struct fp_print_data_item *item = NULL;
int result = -EPROTO; int result = -EPROTO;
if (data_len < sizeof(scan_comp)) { if (data_len < sizeof(scan_comp)) {
@@ -1085,9 +1086,11 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
fp_err("unrecognised data prefix %x %x %x %x %x", fp_err("unrecognised data prefix %x %x %x %x %x",
data[0], data[1], data[2], data[3], data[4]); data[0], data[1], data[2], data[3], data[4]);
} else { } else {
fdata = fpi_print_data_new(dev, data_len - sizeof(scan_comp)); fdata = fpi_print_data_new(dev);
memcpy(fdata->data, data + sizeof(scan_comp), item = fpi_print_data_item_new(data_len - sizeof(scan_comp));
memcpy(item->data, data + sizeof(scan_comp),
data_len - sizeof(scan_comp)); data_len - sizeof(scan_comp));
fdata->prints = g_slist_prepend(fdata->prints, item);
result = FP_ENROLL_COMPLETE; result = FP_ENROLL_COMPLETE;
} }
@@ -1249,12 +1252,13 @@ static void verify_start_sm_run_state(struct fpi_ssm *ssm)
break; break;
case VERIFY_INIT: ; case VERIFY_INIT: ;
struct fp_print_data *print = dev->verify_data; struct fp_print_data *print = dev->verify_data;
size_t data_len = sizeof(verify_hdr) + print->length; struct fp_print_data_item *item = print->prints->data;
size_t data_len = sizeof(verify_hdr) + item->length;
unsigned char *data = g_malloc(data_len); unsigned char *data = g_malloc(data_len);
struct libusb_transfer *transfer; struct libusb_transfer *transfer;
memcpy(data, verify_hdr, sizeof(verify_hdr)); memcpy(data, verify_hdr, sizeof(verify_hdr));
memcpy(data + sizeof(verify_hdr), print->data, print->length); memcpy(data + sizeof(verify_hdr), item->data, item->length);
transfer = alloc_send_cmd28_transfer(dev, 0x03, data, data_len, transfer = alloc_send_cmd28_transfer(dev, 0x03, data, data_len,
verify_init_2803_cb, ssm); verify_init_2803_cb, ssm);
g_free(data); g_free(data);
+1 -7
View File
@@ -64,9 +64,6 @@
/* Best image contrast */ /* Best image contrast */
#define VFS_IMG_BEST_CONRAST 128 #define VFS_IMG_BEST_CONRAST 128
/* Number of enroll stages */
#define VFS_NR_ENROLL 3
/* Device parameters address */ /* Device parameters address */
#define VFS_PAR_000E 0x000e #define VFS_PAR_000E 0x000e
#define VFS_PAR_0011 0x0011 #define VFS_PAR_0011 0x0011
@@ -656,7 +653,7 @@ static int action_completed(struct fp_img_dev *dev)
struct vfs101_dev *vdev = dev->priv; struct vfs101_dev *vdev = dev->priv;
if ((dev->action == IMG_ACTION_ENROLL) && if ((dev->action == IMG_ACTION_ENROLL) &&
(vdev->enroll_stage < VFS_NR_ENROLL)) (vdev->enroll_stage < 1))
/* Enroll not completed, return false */ /* Enroll not completed, return false */
return FALSE; return FALSE;
@@ -1511,9 +1508,6 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
return r; return r;
} }
/* Set enroll stage number */
dev->dev->nr_enroll_stages = VFS_NR_ENROLL;
/* Initialize private structure */ /* Initialize private structure */
vdev = g_malloc0(sizeof(struct vfs101_dev)); vdev = g_malloc0(sizeof(struct vfs101_dev));
vdev->seqnum = -1; vdev->seqnum = -1;
-3
View File
@@ -244,9 +244,6 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
return r; return r;
} }
/* Set enroll stage number */
dev->dev->nr_enroll_stages = 1;
/* Initialize private structure */ /* Initialize private structure */
vdev = g_malloc0(sizeof(vfs301_dev_t)); vdev = g_malloc0(sizeof(vfs301_dev_t));
dev->priv = vdev; dev->priv = vdev;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+47 -9
View File
@@ -91,6 +91,10 @@ enum fp_dev_state {
DEV_STATE_IDENTIFYING, DEV_STATE_IDENTIFYING,
DEV_STATE_IDENTIFY_DONE, DEV_STATE_IDENTIFY_DONE,
DEV_STATE_IDENTIFY_STOPPING, DEV_STATE_IDENTIFY_STOPPING,
DEV_STATE_CAPTURE_STARTING,
DEV_STATE_CAPTURING,
DEV_STATE_CAPTURE_DONE,
DEV_STATE_CAPTURE_STOPPING,
}; };
struct fp_driver **fprint_get_drivers (void); struct fp_driver **fprint_get_drivers (void);
@@ -108,8 +112,8 @@ struct fp_dev {
/* drivers should not mess with any of the below */ /* drivers should not mess with any of the below */
enum fp_dev_state state; enum fp_dev_state state;
int __enroll_stage; int __enroll_stage;
int unconditional_capture;
/* async I/O callbacks and data */ /* async I/O callbacks and data */
/* FIXME: convert this to generic state operational data mechanism? */ /* FIXME: convert this to generic state operational data mechanism? */
@@ -129,6 +133,10 @@ struct fp_dev {
void *identify_cb_data; void *identify_cb_data;
fp_identify_stop_cb identify_stop_cb; fp_identify_stop_cb identify_stop_cb;
void *identify_stop_cb_data; void *identify_stop_cb_data;
fp_capture_cb capture_cb;
void *capture_cb_data;
fp_capture_stop_cb capture_stop_cb;
void *capture_stop_cb_data;
/* FIXME: better place to put this? */ /* FIXME: better place to put this? */
struct fp_print_data **identify_gallery; struct fp_print_data **identify_gallery;
@@ -146,6 +154,7 @@ enum fp_imgdev_action {
IMG_ACTION_ENROLL, IMG_ACTION_ENROLL,
IMG_ACTION_VERIFY, IMG_ACTION_VERIFY,
IMG_ACTION_IDENTIFY, IMG_ACTION_IDENTIFY,
IMG_ACTION_CAPTURE,
}; };
enum fp_imgdev_enroll_state { enum fp_imgdev_enroll_state {
@@ -170,7 +179,9 @@ struct fp_img_dev {
int action_state; int action_state;
struct fp_print_data *acquire_data; struct fp_print_data *acquire_data;
struct fp_print_data *enroll_data;
struct fp_img *acquire_img; struct fp_img *acquire_img;
int enroll_stage;
int action_result; int action_result;
/* FIXME: better place to put this? */ /* FIXME: better place to put this? */
@@ -179,8 +190,6 @@ struct fp_img_dev {
void *priv; void *priv;
}; };
int fpi_imgdev_capture(struct fp_img_dev *imgdev, int unconditional,
struct fp_img **image);
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev); int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev);
int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev); int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev);
@@ -215,6 +224,8 @@ struct fp_driver {
int (*verify_stop)(struct fp_dev *dev, gboolean iterating); int (*verify_stop)(struct fp_dev *dev, gboolean iterating);
int (*identify_start)(struct fp_dev *dev); int (*identify_start)(struct fp_dev *dev);
int (*identify_stop)(struct fp_dev *dev, gboolean iterating); 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); enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv);
@@ -267,6 +278,9 @@ extern struct fp_img_driver aes2550_driver;
#ifdef ENABLE_AES2660 #ifdef ENABLE_AES2660
extern struct fp_img_driver aes2660_driver; extern struct fp_img_driver aes2660_driver;
#endif #endif
#ifdef ENABLE_AES3500
extern struct fp_img_driver aes3500_driver;
#endif
#ifdef ENABLE_AES4000 #ifdef ENABLE_AES4000
extern struct fp_img_driver aes4000_driver; extern struct fp_img_driver aes4000_driver;
#endif #endif
@@ -282,6 +296,15 @@ extern struct fp_img_driver vfs101_driver;
#ifdef ENABLE_VFS301 #ifdef ENABLE_VFS301
extern struct fp_img_driver vfs301_driver; extern struct fp_img_driver vfs301_driver;
#endif #endif
#ifdef ENABLE_VFS5011
extern struct fp_img_driver vfs5011_driver;
#endif
#ifdef ENABLE_UPEKTC_IMG
extern struct fp_img_driver upektc_img_driver;
#endif
#ifdef ENABLE_ETES603
extern struct fp_img_driver etes603_driver;
#endif
extern libusb_context *fpi_usb_ctx; extern libusb_context *fpi_usb_ctx;
extern GSList *opened_devices; extern GSList *opened_devices;
@@ -310,15 +333,19 @@ enum fp_print_data_type {
PRINT_DATA_NBIS_MINUTIAE, PRINT_DATA_NBIS_MINUTIAE,
}; };
struct fp_print_data { struct fp_print_data_item {
uint16_t driver_id;
uint32_t devtype;
enum fp_print_data_type type;
size_t length; size_t length;
unsigned char data[0]; unsigned char data[0];
}; };
struct fpi_print_data_fp1 { 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]; char prefix[3];
uint16_t driver_id; uint16_t driver_id;
uint32_t devtype; uint32_t devtype;
@@ -326,8 +353,14 @@ struct fpi_print_data_fp1 {
unsigned char data[0]; unsigned char data[0];
} __attribute__((__packed__)); } __attribute__((__packed__));
struct fpi_print_data_item_fp2 {
uint32_t length;
unsigned char data[0];
} __attribute__((__packed__));
void fpi_data_exit(void); void fpi_data_exit(void);
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev, size_t length); 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, 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 type1, uint16_t driver_id2, uint32_t devtype2,
enum fp_print_data_type type2); enum fp_print_data_type type2);
@@ -436,6 +469,11 @@ void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
size_t match_offset, struct fp_img *img); size_t match_offset, struct fp_img *img);
void fpi_drvcb_identify_stopped(struct fp_dev *dev); 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 */ /* for image drivers */
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status); 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_close_complete(struct fp_img_dev *imgdev);
+1 -1
View File
@@ -74,7 +74,7 @@ static void print_driver (struct fp_driver *driver)
if (num_printed == 0) if (num_printed == 0)
printf ("# %s\n", driver->full_name); printf ("# %s\n", driver->full_name);
printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", ATTR{power/control}=\"auto\"\n", driver->id_table[i].vendor, driver->id_table[i].product); printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n", driver->id_table[i].vendor, driver->id_table[i].product);
num_printed++; num_printed++;
} }
+18
View File
@@ -107,6 +107,17 @@ uint32_t fp_dev_get_devtype(struct fp_dev *dev);
int fp_dev_supports_print_data(struct fp_dev *dev, struct fp_print_data *data); int fp_dev_supports_print_data(struct fp_dev *dev, struct fp_print_data *data);
int fp_dev_supports_dscv_print(struct fp_dev *dev, struct fp_dscv_print *print); int fp_dev_supports_dscv_print(struct fp_dev *dev, struct fp_dscv_print *print);
/** \ingroup dev
* Image capture result codes returned from fp_dev_img_capture().
*/
enum fp_capture_result {
/** Capture completed successfully, the capture data has been
* returned to the caller. */
FP_CAPTURE_COMPLETE = 0,
/** Capture failed for some reason */
FP_CAPTURE_FAIL,
};
int fp_dev_supports_imaging(struct fp_dev *dev); int fp_dev_supports_imaging(struct fp_dev *dev);
int fp_dev_img_capture(struct fp_dev *dev, int unconditional, int fp_dev_img_capture(struct fp_dev *dev, int unconditional,
struct fp_img **image); struct fp_img **image);
@@ -340,6 +351,13 @@ typedef void (*fp_identify_stop_cb)(struct fp_dev *dev, void *user_data);
int fp_async_identify_stop(struct fp_dev *dev, fp_identify_stop_cb callback, int fp_async_identify_stop(struct fp_dev *dev, fp_identify_stop_cb callback,
void *user_data); void *user_data);
typedef void (*fp_capture_cb)(struct fp_dev *dev, int result,
struct fp_img *img, void *user_data);
int fp_async_capture_start(struct fp_dev *dev, int unconditional, fp_capture_cb callback, void *user_data);
typedef void (*fp_capture_stop_cb)(struct fp_dev *dev, void *user_data);
int fp_async_capture_stop(struct fp_dev *dev, fp_capture_stop_cb callback, void *user_data);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
-88
View File
@@ -1,88 +0,0 @@
/*
* Imaging utility functions for libfprint
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "fp_internal.h"
struct fp_img *fpi_im_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;
GdkPixbuf *orig, *resized;
struct fp_img *newimg;
guchar *pixels;
guint y;
int rowstride;
g_type_init ();
/* It is possible to implement resizing using a simple algorithm, however
* we use gdk-pixbuf because it applies some kind of smoothing to the
* result, which improves matching performances in my experiments. */
/* Create the original pixbuf, and fill it in from the grayscale data */
orig = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
FALSE,
8,
img->width,
img->height);
rowstride = gdk_pixbuf_get_rowstride (orig);
pixels = gdk_pixbuf_get_pixels (orig);
for (y = 0; y < img->height; y++) {
guint x;
for (x = 0; x < img->width; x++) {
guchar *p, *r;
p = pixels + y * rowstride + x * 3;
r = img->data + y * img->width + x;
p[0] = r[0];
p[1] = r[0];
p[2] = r[0];
}
}
/* Resize the pixbuf, and create the new fp_img */
resized = gdk_pixbuf_scale_simple (orig, new_width, new_height, GDK_INTERP_HYPER);
g_object_unref (orig);
newimg = fpi_img_new(new_width * new_height);
newimg->width = new_width;
newimg->height = new_height;
newimg->flags = img->flags;
rowstride = gdk_pixbuf_get_rowstride (resized);
pixels = gdk_pixbuf_get_pixels (resized);
for (y = 0; y < newimg->height; y++) {
guint x;
for (x = 0; x < newimg->width; x++) {
guchar *p, *r;
r = newimg->data + y * newimg->width + x;
p = pixels + y * rowstride + x * 3;
r[0] = p[0];
}
}
g_object_unref (resized);
return newimg;
}
+56 -22
View File
@@ -313,6 +313,7 @@ int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
struct fp_print_data **ret) struct fp_print_data **ret)
{ {
struct fp_print_data *print; struct fp_print_data *print;
struct fp_print_data_item *item;
int r; int r;
if (!img->minutiae) { if (!img->minutiae) {
@@ -327,9 +328,11 @@ 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 /* FIXME: space is wasted if we dont hit the max minutiae count. would
* be good to make this dynamic. */ * be good to make this dynamic. */
print = fpi_print_data_new(imgdev->dev, sizeof(struct xyt_struct)); print = fpi_print_data_new(imgdev->dev);
item = fpi_print_data_item_new(sizeof(struct xyt_struct));
print->type = PRINT_DATA_NBIS_MINUTIAE; print->type = PRINT_DATA_NBIS_MINUTIAE;
minutiae_to_xyt(img->minutiae, img->width, img->height, print->data); minutiae_to_xyt(img->minutiae, img->width, img->height, item->data);
print->prints = g_slist_prepend(print->prints, item);
/* FIXME: the print buffer at this point is endian-specific, and will /* FIXME: the print buffer at this point is endian-specific, and will
* only work when loaded onto machines with identical endianness. not good! * only work when loaded onto machines with identical endianness. not good!
@@ -342,42 +345,73 @@ int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
int fpi_img_compare_print_data(struct fp_print_data *enrolled_print, int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
struct fp_print_data *new_print) struct fp_print_data *new_print)
{ {
struct xyt_struct *gstruct = (struct xyt_struct *) enrolled_print->data; int score, max_score = 0, probe_len;
struct xyt_struct *pstruct = (struct xyt_struct *) new_print->data; struct xyt_struct *pstruct = NULL;
GTimer *timer; struct xyt_struct *gstruct = NULL;
int r; struct fp_print_data_item *data_item;
GSList *list_item;
if (enrolled_print->type != PRINT_DATA_NBIS_MINUTIAE || if (enrolled_print->type != PRINT_DATA_NBIS_MINUTIAE ||
new_print->type != PRINT_DATA_NBIS_MINUTIAE) { new_print->type != PRINT_DATA_NBIS_MINUTIAE) {
fp_err("invalid print format"); fp_err("invalid print format");
return -EINVAL; return -EINVAL;
} }
timer = g_timer_new(); if (g_slist_length(new_print->prints) != 1) {
r = bozorth_main(pstruct, gstruct); fp_err("new_print contains more than one sample, is it enrolled print?");
g_timer_stop(timer); return -EINVAL;
fp_dbg("bozorth processing took %f seconds, score=%d", }
g_timer_elapsed(timer, NULL), r);
g_timer_destroy(timer);
return r; data_item = new_print->prints->data;
pstruct = (struct xyt_struct *)data_item->data;
probe_len = bozorth_probe_init(pstruct);
list_item = enrolled_print->prints;
do {
data_item = list_item->data;
gstruct = (struct xyt_struct *)data_item->data;
score = bozorth_to_gallery(probe_len, pstruct, gstruct);
fp_dbg("score %d", score);
max_score = max(score, max_score);
list_item = g_slist_next(list_item);
} while (list_item);
return max_score;
} }
int fpi_img_compare_print_data_to_gallery(struct fp_print_data *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_print_data **gallery, int match_threshold, size_t *match_offset)
{ {
struct xyt_struct *pstruct = (struct xyt_struct *) print->data; struct xyt_struct *pstruct;
struct xyt_struct *gstruct;
struct fp_print_data *gallery_print; struct fp_print_data *gallery_print;
int probe_len = bozorth_probe_init(pstruct); struct fp_print_data_item *data_item;
int probe_len;
size_t i = 0; size_t i = 0;
int r;
GSList *list_item;
if (g_slist_length(print->prints) != 1) {
fp_err("new_print contains more than one sample, is it enrolled print?");
return -EINVAL;
}
data_item = print->prints->data;
pstruct = (struct xyt_struct *)data_item->data;
probe_len = bozorth_probe_init(pstruct);
while ((gallery_print = gallery[i++])) { while ((gallery_print = gallery[i++])) {
struct xyt_struct *gstruct = (struct xyt_struct *) gallery_print->data; list_item = gallery_print->prints;
int r = bozorth_to_gallery(probe_len, pstruct, gstruct); do {
if (r >= match_threshold) { data_item = list_item->data;
*match_offset = i - 1; gstruct = (struct xyt_struct *)data_item->data;
return FP_VERIFY_MATCH; r = bozorth_to_gallery(probe_len, pstruct, gstruct);
} if (r >= match_threshold) {
*match_offset = i - 1;
return FP_VERIFY_MATCH;
}
list_item = g_slist_next(list_item);
} while (list_item);
} }
return FP_VERIFY_NO_MATCH; return FP_VERIFY_NO_MATCH;
} }
+76 -15
View File
@@ -25,6 +25,7 @@
#define MIN_ACCEPTABLE_MINUTIAE 10 #define MIN_ACCEPTABLE_MINUTIAE 10
#define BOZORTH3_DEFAULT_THRESHOLD 40 #define BOZORTH3_DEFAULT_THRESHOLD 40
#define IMG_ENROLL_STAGES 5
static int img_dev_open(struct fp_dev *dev, unsigned long driver_data) static int img_dev_open(struct fp_dev *dev, unsigned long driver_data)
{ {
@@ -33,8 +34,9 @@ static int img_dev_open(struct fp_dev *dev, unsigned long driver_data)
int r = 0; int r = 0;
imgdev->dev = dev; imgdev->dev = dev;
imgdev->enroll_stage = 0;
dev->priv = imgdev; dev->priv = imgdev;
dev->nr_enroll_stages = 1; dev->nr_enroll_stages = IMG_ENROLL_STAGES;
/* for consistency in driver code, allow udev access through imgdev */ /* for consistency in driver code, allow udev access through imgdev */
imgdev->udev = dev->udev; imgdev->udev = dev->udev;
@@ -144,7 +146,13 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
switch (imgdev->action) { switch (imgdev->action) {
case IMG_ACTION_ENROLL: case IMG_ACTION_ENROLL:
fp_dbg("reporting enroll result"); fp_dbg("reporting enroll result");
fpi_drvcb_enroll_stage_completed(imgdev->dev, r, data, img); data = imgdev->enroll_data;
if (r == FP_ENROLL_COMPLETE) {
imgdev->enroll_data = NULL;
}
fpi_drvcb_enroll_stage_completed(imgdev->dev, r,
r == FP_ENROLL_COMPLETE ? data : NULL,
img);
/* the callback can cancel enrollment, so recheck current /* the callback can cancel enrollment, so recheck current
* action and the status to see if retry is needed */ * action and the status to see if retry is needed */
if (imgdev->action == IMG_ACTION_ENROLL && if (imgdev->action == IMG_ACTION_ENROLL &&
@@ -163,6 +171,9 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
imgdev->identify_match_offset, img); imgdev->identify_match_offset, img);
fp_print_data_free(data); fp_print_data_free(data);
break; break;
case IMG_ACTION_CAPTURE:
fpi_drvcb_report_capture_result(imgdev->dev, r, img);
break;
default: default:
fp_err("unhandled action %d", imgdev->action); fp_err("unhandled action %d", imgdev->action);
break; break;
@@ -231,24 +242,41 @@ void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
fp_img_standardize(img); fp_img_standardize(img);
imgdev->acquire_img = img; imgdev->acquire_img = img;
r = fpi_img_to_print_data(imgdev, img, &print); if (imgdev->action != IMG_ACTION_CAPTURE) {
if (r < 0) { r = fpi_img_to_print_data(imgdev, img, &print);
fp_dbg("image to print data conversion error: %d", r); if (r < 0) {
imgdev->action_result = FP_ENROLL_RETRY; fp_dbg("image to print data conversion error: %d", r);
goto next_state; imgdev->action_result = FP_ENROLL_RETRY;
} else if (img->minutiae->num < MIN_ACCEPTABLE_MINUTIAE) { goto next_state;
fp_dbg("not enough minutiae, %d/%d", img->minutiae->num, } else if (img->minutiae->num < MIN_ACCEPTABLE_MINUTIAE) {
MIN_ACCEPTABLE_MINUTIAE); fp_dbg("not enough minutiae, %d/%d", img->minutiae->num,
fp_print_data_free(print); MIN_ACCEPTABLE_MINUTIAE);
/* depends on FP_ENROLL_RETRY == FP_VERIFY_RETRY */ fp_print_data_free(print);
imgdev->action_result = FP_ENROLL_RETRY; /* depends on FP_ENROLL_RETRY == FP_VERIFY_RETRY */
goto next_state; imgdev->action_result = FP_ENROLL_RETRY;
goto next_state;
}
} }
imgdev->acquire_data = print; imgdev->acquire_data = print;
switch (imgdev->action) { switch (imgdev->action) {
case IMG_ACTION_ENROLL: case IMG_ACTION_ENROLL:
imgdev->action_result = FP_ENROLL_COMPLETE; if (!imgdev->enroll_data) {
imgdev->enroll_data = fpi_print_data_new(imgdev->dev);
}
BUG_ON(g_slist_length(print->prints) != 1);
/* Move print data from acquire data into enroll_data */
imgdev->enroll_data->prints =
g_slist_prepend(imgdev->enroll_data->prints, print->prints->data);
print->prints = g_slist_remove(print->prints, print->prints->data);
fp_print_data_free(imgdev->acquire_data);
imgdev->acquire_data = NULL;
imgdev->enroll_stage++;
if (imgdev->enroll_stage == imgdev->dev->nr_enroll_stages)
imgdev->action_result = FP_ENROLL_COMPLETE;
else
imgdev->action_result = FP_ENROLL_PASS;
break; break;
case IMG_ACTION_VERIFY: case IMG_ACTION_VERIFY:
verify_process_img(imgdev); verify_process_img(imgdev);
@@ -256,6 +284,9 @@ void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
case IMG_ACTION_IDENTIFY: case IMG_ACTION_IDENTIFY:
identify_process_img(imgdev); identify_process_img(imgdev);
break; break;
case IMG_ACTION_CAPTURE:
imgdev->action_result = FP_CAPTURE_COMPLETE;
break;
default: default:
BUG(); BUG();
break; break;
@@ -280,6 +311,9 @@ void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error)
case IMG_ACTION_IDENTIFY: case IMG_ACTION_IDENTIFY:
fpi_drvcb_report_identify_result(imgdev->dev, error, 0, NULL); fpi_drvcb_report_identify_result(imgdev->dev, error, 0, NULL);
break; break;
case IMG_ACTION_CAPTURE:
fpi_drvcb_report_capture_result(imgdev->dev, error, NULL);
break;
default: default:
fp_err("unhandled action %d", imgdev->action); fp_err("unhandled action %d", imgdev->action);
break; break;
@@ -300,6 +334,9 @@ void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status)
case IMG_ACTION_IDENTIFY: case IMG_ACTION_IDENTIFY:
fpi_drvcb_identify_started(imgdev->dev, status); fpi_drvcb_identify_started(imgdev->dev, status);
break; break;
case IMG_ACTION_CAPTURE:
fpi_drvcb_capture_started(imgdev->dev, status);
break;
default: default:
fp_err("unhandled action %d", imgdev->action); fp_err("unhandled action %d", imgdev->action);
return; return;
@@ -325,6 +362,9 @@ void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev)
case IMG_ACTION_IDENTIFY: case IMG_ACTION_IDENTIFY:
fpi_drvcb_identify_stopped(imgdev->dev); fpi_drvcb_identify_stopped(imgdev->dev);
break; break;
case IMG_ACTION_CAPTURE:
fpi_drvcb_capture_stopped(imgdev->dev);
break;
default: default:
fp_err("unhandled action %d", imgdev->action); fp_err("unhandled action %d", imgdev->action);
break; break;
@@ -385,6 +425,7 @@ static int generic_acquire_start(struct fp_dev *dev, int action)
fp_dbg("action %d", action); fp_dbg("action %d", action);
imgdev->action = action; imgdev->action = action;
imgdev->action_state = IMG_ACQUIRE_STATE_ACTIVATING; imgdev->action_state = IMG_ACQUIRE_STATE_ACTIVATING;
imgdev->enroll_stage = 0;
r = dev_activate(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON); r = dev_activate(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON);
if (r < 0) if (r < 0)
@@ -400,8 +441,10 @@ static void generic_acquire_stop(struct fp_img_dev *imgdev)
dev_deactivate(imgdev); dev_deactivate(imgdev);
fp_print_data_free(imgdev->acquire_data); fp_print_data_free(imgdev->acquire_data);
fp_print_data_free(imgdev->enroll_data);
fp_img_free(imgdev->acquire_img); fp_img_free(imgdev->acquire_img);
imgdev->acquire_data = NULL; imgdev->acquire_data = NULL;
imgdev->enroll_data = NULL;
imgdev->acquire_img = NULL; imgdev->acquire_img = NULL;
imgdev->action_result = 0; imgdev->action_result = 0;
} }
@@ -421,6 +464,14 @@ static int img_dev_identify_start(struct fp_dev *dev)
return generic_acquire_start(dev, IMG_ACTION_IDENTIFY); return generic_acquire_start(dev, IMG_ACTION_IDENTIFY);
} }
static int img_dev_capture_start(struct fp_dev *dev)
{
/* Unconditional capture is not supported yet */
if (dev->unconditional_capture)
return -ENOTSUP;
return generic_acquire_start(dev, IMG_ACTION_CAPTURE);
}
static int img_dev_enroll_stop(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->priv;
@@ -446,6 +497,14 @@ static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating)
return 0; return 0;
} }
static int img_dev_capture_stop(struct fp_dev *dev)
{
struct fp_img_dev *imgdev = dev->priv;
BUG_ON(imgdev->action != IMG_ACTION_CAPTURE);
generic_acquire_stop(imgdev);
return 0;
}
void fpi_img_driver_setup(struct fp_img_driver *idriver) void fpi_img_driver_setup(struct fp_img_driver *idriver)
{ {
idriver->driver.type = DRIVER_IMAGING; idriver->driver.type = DRIVER_IMAGING;
@@ -457,5 +516,7 @@ void fpi_img_driver_setup(struct fp_img_driver *idriver)
idriver->driver.verify_stop = img_dev_verify_stop; idriver->driver.verify_stop = img_dev_verify_stop;
idriver->driver.identify_start = img_dev_identify_start; idriver->driver.identify_start = img_dev_identify_start;
idriver->driver.identify_stop = img_dev_identify_stop; idriver->driver.identify_stop = img_dev_identify_stop;
idriver->driver.capture_start = img_dev_capture_start;
idriver->driver.capture_stop = img_dev_capture_stop;
} }
+23 -27
View File
@@ -1,6 +1,7 @@
/* /*
* Imaging utility functions for libfprint * Imaging utility functions for libfprint
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
* Copyright (C) 2013 Vasily Khoruzhick <anarsoul@gmail.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@@ -17,50 +18,45 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <errno.h> #include <pixman.h>
#include <magick/ImageMagick.h> #include <string.h>
#include "fp_internal.h" #include "fp_internal.h"
struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor) struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor)
{ {
Image *mimg;
Image *resized;
ExceptionInfo exception;
MagickBooleanType ret;
int new_width = img->width * w_factor; int new_width = img->width * w_factor;
int new_height = img->height * h_factor; int new_height = img->height * h_factor;
pixman_image_t *orig, *resized;
pixman_transform_t transform;
struct fp_img *newimg; struct fp_img *newimg;
/* It is possible to implement resizing using a simple algorithm, however orig = pixman_image_create_bits(PIXMAN_a8, img->width, img->height, (uint32_t *)img->data, img->width);
* we use ImageMagick because it applies some kind of smoothing to the resized = pixman_image_create_bits(PIXMAN_a8, new_width, new_height, NULL, new_width);
* result, which improves matching performances in my experiments. */
if (!IsMagickInstantiated()) pixman_transform_init_identity(&transform);
InitializeMagick(NULL); pixman_transform_scale(NULL, &transform, pixman_int_to_fixed(w_factor), pixman_int_to_fixed(h_factor));
pixman_image_set_transform(orig, &transform);
GetExceptionInfo(&exception); pixman_image_set_filter(orig, PIXMAN_FILTER_BILINEAR, NULL, 0);
mimg = ConstituteImage(img->width, img->height, "I", CharPixel, img->data, pixman_image_composite32(PIXMAN_OP_SRC,
&exception); orig, /* src */
NULL, /* mask */
GetExceptionInfo(&exception); resized, /* dst */
resized = ResizeImage(mimg, new_width, new_height, 0, 1.0, &exception); 0, 0, /* src x y */
0, 0, /* mask x y */
0, 0, /* dst x y */
new_width, new_height /* width height */
);
newimg = fpi_img_new(new_width * new_height); newimg = fpi_img_new(new_width * new_height);
newimg->width = new_width; newimg->width = new_width;
newimg->height = new_height; newimg->height = new_height;
newimg->flags = img->flags; newimg->flags = img->flags;
GetExceptionInfo(&exception); memcpy(newimg->data, pixman_image_get_data(resized), new_width * new_height);
ret = ExportImagePixels(resized, 0, 0, new_width, new_height, "I",
CharPixel, newimg->data, &exception);
if (ret != MagickTrue) {
fp_err("export failed");
return NULL;
}
DestroyImage(mimg); pixman_image_unref(orig);
DestroyImage(resized); pixman_image_unref(resized);
return newimg; return newimg;
} }
+97
View File
@@ -512,3 +512,100 @@ err:
return r; return r;
} }
struct sync_capture_data {
gboolean populated;
int result;
struct fp_img *img;
};
static void sync_capture_cb(struct fp_dev *dev, int result, struct fp_img *img,
void *user_data)
{
struct sync_capture_data *vdata = user_data;
vdata->result = result;
vdata->img = img;
vdata->populated = TRUE;
}
static void capture_stop_cb(struct fp_dev *dev, void *user_data)
{
gboolean *stopped = user_data;
fp_dbg("");
*stopped = TRUE;
}
/** \ingroup dev
* Captures an \ref img "image" from a device. The returned image is the raw
* image provided by the device, you may wish to \ref img_std "standardize" it.
*
* If set, the <tt>unconditional</tt> flag indicates that the device should
* capture an image unconditionally, regardless of whether a finger is there
* or not. If unset, this function will block until a finger is detected on
* the sensor.
*
* \param dev the device
* \param unconditional whether to unconditionally capture an image, or to only capture when a finger is detected
* \param img a location to return the captured image. Must be freed with
* fp_img_free() after use.
* \return 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.
* \sa fp_dev_supports_imaging()
*/
API_EXPORTED int fp_dev_img_capture(struct fp_dev *dev, int unconditional,
struct fp_img **img)
{
struct sync_capture_data *vdata;
gboolean stopped = FALSE;
int r;
if (!dev->drv->capture_start) {
fp_dbg("image capture is not supported on %s device", dev->drv->name);
return -ENOTSUP;
}
fp_dbg("to be handled by %s", dev->drv->name);
vdata = g_malloc0(sizeof(struct sync_capture_data));
r = fp_async_capture_start(dev, unconditional, sync_capture_cb, vdata);
if (r < 0) {
fp_dbg("capture_start error %d", r);
g_free(vdata);
return r;
}
while (!vdata->populated) {
r = fp_handle_events();
if (r < 0) {
g_free(vdata);
goto err;
}
}
if (img)
*img = vdata->img;
else
fp_img_free(vdata->img);
r = vdata->result;
g_free(vdata);
switch (r) {
case FP_CAPTURE_COMPLETE:
fp_dbg("result: complete");
break;
case FP_CAPTURE_FAIL:
fp_dbg("result: fail");
break;
default:
fp_err("unrecognised return code %d", r);
r = -EINVAL;
}
err:
fp_dbg("ending capture");
if (fp_async_capture_stop(dev, capture_stop_cb, &stopped) == 0)
while (!stopped)
if (fp_handle_events() < 0)
break;
return r;
}