Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 408804 Details for
Bug 531698
sys-auth/libfprint-0.6.0 - add support for vfs 0050 fingerprint scanner (and others from upstream)
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
libfprint-0.6.0_vfs0050.patch
libfprint-0.6.0_vfs0050.patch (text/plain), 41.84 KB, created by
Matthew Schultz
on 2015-08-11 16:05:34 UTC
(
hide
)
Description:
libfprint-0.6.0_vfs0050.patch
Filename:
MIME Type:
Creator:
Matthew Schultz
Created:
2015-08-11 16:05:34 UTC
Size:
41.84 KB
patch
obsolete
>diff --git a/configure.ac b/configure.ac >index 707f587..58ea9e9 100644 >--- a/configure.ac >+++ b/configure.ac >@@ -23,7 +23,7 @@ AC_SUBST(lt_major) > AC_SUBST(lt_revision) > AC_SUBST(lt_age) > >-all_drivers="upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes1660 aes2501 aes2550 aes2660 aes3500 aes4000 vfs101 vfs301 vfs5011 upektc_img etes603" >+all_drivers="upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes1660 aes2501 aes2550 aes2660 aes3500 aes4000 vfs101 vfs301 vfs5011 upektc_img etes603 vfs0050" > > require_imaging='no' > require_aeslib='no' >@@ -48,6 +48,7 @@ enable_vfs301='no' > enable_vfs5011='no' > enable_upektc_img='no' > enable_etes603='no' >+enable_vfs0050='no' > > AC_ARG_WITH([drivers],[AS_HELP_STRING([--with-drivers], > [List of drivers to enable])], >@@ -150,6 +151,10 @@ for driver in `echo ${drivers} | sed -e 's/,/ /g' -e 's/,$//g'`; do > AC_DEFINE([ENABLE_ETES603], [], [Build EgisTec ES603 driver]) > enable_etes603="yes" > ;; >+ vfs0050) >+ AC_DEFINE([ENABLE_VFS0050], [], [Build Validity VFS0050 driver]) >+ enable_vfs0050="yes" >+ ;; > esac > done > >@@ -175,6 +180,7 @@ AM_CONDITIONAL([ENABLE_VFS301], [test "$enable_vfs301" = "yes"]) > AM_CONDITIONAL([ENABLE_VFS5011], [test "$enable_vfs5011" = "yes"]) > AM_CONDITIONAL([ENABLE_UPEKTC_IMG], [test "$enable_upektc_img" = "yes"]) > AM_CONDITIONAL([ENABLE_ETES603], [test "$enable_etes603" = "yes"]) >+AM_CONDITIONAL([ENABLE_VFS0050], [test "$enable_vfs0050" = "yes"]) > > > PKG_CHECK_MODULES(LIBUSB, [libusb-1.0 >= 0.9.1]) >@@ -396,6 +402,11 @@ if test x$enable_etes603 != xno ; then > else > AC_MSG_NOTICE([ etes603 driver disabled]) > fi >+if test x$enable_vfs0050 != xno ; then >+ AC_MSG_NOTICE([** vfs0050 driver enabled]) >+else >+ AC_MSG_NOTICE([ vfs0050 driver disabled]) >+fi > if test x$require_aeslib != xno ; then > AC_MSG_NOTICE([** aeslib helper functions enabled]) > else >diff --git a/libfprint/Makefile.am b/libfprint/Makefile.am >index b86d0f8..080a350 100644 >--- a/libfprint/Makefile.am >+++ b/libfprint/Makefile.am >@@ -21,6 +21,7 @@ VFS301_SRC = drivers/vfs301.c drivers/vfs301_proto.c drivers/vfs301_proto.h dri > VFS5011_SRC = drivers/vfs5011.c drivers/vfs5011_proto.h > UPEKTC_IMG_SRC = drivers/upektc_img.c drivers/upektc_img.h > ETES603_SRC = drivers/etes603.c >+VFS0050_SRC = drivers/vfs0050.c drivers/vfs0050.h > > EXTRA_DIST = \ > $(UPEKE2_SRC) \ >@@ -42,6 +43,7 @@ EXTRA_DIST = \ > $(VFS5011_SRC) \ > $(UPEKTC_IMG_SRC) \ > $(ETES603_SRC) \ >+ $(VFS0050_SRC) \ > drivers/aesx660.c \ > drivers/aesx660.h \ > drivers/aes3k.c \ >@@ -182,6 +184,10 @@ if ENABLE_ETES603 > DRIVER_SRC += $(ETES603_SRC) > endif > >+if ENABLE_VFS0050 >+DRIVER_SRC += $(VFS0050_SRC) >+endif >+ > if REQUIRE_PIXMAN > OTHER_SRC += pixman.c > libfprint_la_CFLAGS += $(IMAGING_CFLAGS) >diff --git a/libfprint/core.c b/libfprint/core.c >index 2ae7649..8b6fe43 100644 >--- a/libfprint/core.c >+++ b/libfprint/core.c >@@ -398,6 +398,9 @@ static struct fp_img_driver * const img_drivers[] = { > #ifdef ENABLE_ETES603 > &etes603_driver, > #endif >+#ifdef ENABLE_VFS0050 >+ &vfs0050_driver, >+#endif > /*#ifdef ENABLE_FDU2000 > &fdu2000_driver, > #endif >diff --git a/libfprint/drivers/driver_ids.h b/libfprint/drivers/driver_ids.h >index 4d8414c..8143d01 100644 >--- a/libfprint/drivers/driver_ids.h >+++ b/libfprint/drivers/driver_ids.h >@@ -40,6 +40,7 @@ enum { > UPEKTC_IMG_ID = 17, > ETES603_ID = 18, > VFS5011_ID = 19, >+ VFS0050_ID = 20, > }; > > #endif >diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c >new file mode 100644 >index 0000000..6fa7d2a >--- /dev/null >+++ b/libfprint/drivers/vfs0050.c >@@ -0,0 +1,761 @@ >+/* >+ * Validity VFS0050 driver for libfprint >+ * Copyright (C) 2015 Konstantin Semenov <zemen17@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 "vfs0050" >+ >+#include <errno.h> >+#include <fp_internal.h> >+#include "driver_ids.h" >+ >+#include <memory.h> >+ >+#include "vfs0050.h" >+ >+/* USB functions */ >+ >+/* Callback for async_write */ >+static void async_write_callback(struct libusb_transfer *transfer) >+{ >+ struct fpi_ssm *ssm = transfer->user_data; >+ struct fp_img_dev *idev = ssm->priv; >+ >+ int transferred = transfer->actual_length, error = >+ transfer->status, len = transfer->length; >+ >+ libusb_free_transfer(transfer); >+ >+ if (error != 0) { >+ fp_err("USB write transfer: %s", libusb_error_name(error)); >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ return; >+ } >+ >+ if (transferred != len) { >+ fp_err("Written only %d of %d bytes", transferred, len); >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ return; >+ } >+ >+ fpi_ssm_next_state(ssm); >+} >+ >+/* Send data to EP1, the only out endpoint */ >+static void async_write(struct fpi_ssm *ssm, void *data, int len) >+{ >+ struct fp_img_dev *idev = ssm->priv; >+ struct libusb_device_handle *udev = idev->udev; >+ struct vfs_dev_t *vdev = idev->priv; >+ >+ vdev->transfer = libusb_alloc_transfer(0); >+ libusb_fill_bulk_transfer(vdev->transfer, udev, 0x01, data, len, >+ async_write_callback, ssm, VFS_USB_TIMEOUT); >+ libusb_submit_transfer(vdev->transfer); >+} >+ >+/* Callback for async_read */ >+static void async_read_callback(struct libusb_transfer *transfer) >+{ >+ struct fpi_ssm *ssm = transfer->user_data; >+ struct fp_img_dev *idev = ssm->priv; >+ >+ int transferred = transfer->actual_length, error = >+ transfer->status, len = transfer->length; >+ int ep = transfer->endpoint; >+ >+ libusb_free_transfer(transfer); >+ >+ if (error != 0) { >+ fp_err("USB read transfer on endpoint %d: %s", ep - 0x80, >+ libusb_error_name(error)); >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ return; >+ } >+ >+ if (transferred != len) { >+ fp_err("Received %d instead of %d bytes", transferred, len); >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ return; >+ } >+ >+ fpi_ssm_next_state(ssm); >+} >+ >+/* Receive data from the given ep and compare with expected */ >+static void async_read(struct fpi_ssm *ssm, int ep, void *data, int len) >+{ >+ struct fp_img_dev *idev = ssm->priv; >+ struct libusb_device_handle *udev = idev->udev; >+ struct vfs_dev_t *vdev = idev->priv; >+ >+ ep += 0x80; >+ >+ vdev->transfer = libusb_alloc_transfer(0); >+ >+ /* 0x83 is the only interrupt endpoint */ >+ if (ep == 0x83) >+ libusb_fill_interrupt_transfer(vdev->transfer, udev, ep, data, >+ len, async_read_callback, ssm, >+ VFS_USB_TIMEOUT); >+ else >+ libusb_fill_bulk_transfer(vdev->transfer, udev, ep, data, len, >+ async_read_callback, ssm, >+ VFS_USB_TIMEOUT); >+ libusb_submit_transfer(vdev->transfer); >+} >+ >+/* Callback for async_read */ >+static void async_abort_callback(struct libusb_transfer *transfer) >+{ >+ struct fpi_ssm *ssm = transfer->user_data; >+ struct fp_img_dev *idev = ssm->priv; >+ >+ int transferred = transfer->actual_length, error = transfer->status; >+ int ep = transfer->endpoint; >+ >+ /* Free trash buffer, we don't need it */ >+ g_free(transfer->buffer); >+ libusb_free_transfer(transfer); >+ >+ /* In normal case endpoint is empty */ >+ if (error == LIBUSB_TRANSFER_TIMED_OUT) { >+ fpi_ssm_next_state(ssm); >+ return; >+ } >+ >+ if (error != 0) { >+ fp_err("USB write transfer: %s", libusb_error_name(error)); >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ return; >+ } >+ >+ /* Don't stop process, only print warning */ >+ if (transferred > 0) >+ fp_warn("Endpoint %d had extra %d bytes", ep - 0x80, >+ transferred); >+ >+ fpi_ssm_jump_to_state(ssm, ssm->cur_state); >+} >+ >+/* Receive data from the given ep and compare with expected */ >+static void async_abort(struct fpi_ssm *ssm, int ep) >+{ >+ struct fp_img_dev *idev = ssm->priv; >+ struct libusb_device_handle *udev = idev->udev; >+ struct vfs_dev_t *vdev = idev->priv; >+ >+ int len = VFS_USB_BUFFER_SIZE; >+ unsigned char *data = g_malloc(VFS_USB_BUFFER_SIZE); >+ >+ ep += 0x80; >+ >+ vdev->transfer = libusb_alloc_transfer(0); >+ >+ /* 0x83 is the only interrupt endpoint */ >+ if (ep == 0x83) >+ libusb_fill_interrupt_transfer(vdev->transfer, udev, ep, data, >+ len, async_abort_callback, ssm, >+ VFS_USB_ABORT_TIMEOUT); >+ else >+ libusb_fill_bulk_transfer(vdev->transfer, udev, ep, data, len, >+ async_abort_callback, ssm, >+ VFS_USB_ABORT_TIMEOUT); >+ libusb_submit_transfer(vdev->transfer); >+} >+ >+/* Proto functions */ >+ >+/* SSM loop for clear_ep2 */ >+static void clear_ep2_ssm(struct fpi_ssm *ssm) >+{ >+ struct fp_img_dev *idev = ssm->priv; >+ >+ short result; >+ char command04 = 0x04; >+ >+ switch (ssm->cur_state) { >+ case SUBSM1_COMMAND_04: >+ async_write(ssm, &command04, sizeof(command04)); >+ break; >+ >+ case SUBSM1_RETURN_CODE: >+ async_read(ssm, 1, &result, sizeof(result)); >+ break; >+ >+ case SUBSM1_ABORT_2: >+ async_abort(ssm, 2); >+ break; >+ >+ default: >+ fp_err("Unknown SUBSM1 state"); >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ } >+} >+ >+/* Send command to clear EP2 */ >+static void clear_ep2(struct fpi_ssm *ssm) >+{ >+ struct fp_img_dev *idev = ssm->priv; >+ >+ struct fpi_ssm *subsm = >+ fpi_ssm_new(idev->dev, clear_ep2_ssm, SUBSM1_STATES); >+ subsm->priv = idev; >+ fpi_ssm_start_subsm(ssm, subsm); >+} >+ >+static void send_control_packet_ssm(struct fpi_ssm *ssm) >+{ >+ struct fp_img_dev *idev = ssm->priv; >+ struct vfs_dev_t *vdev = idev->priv; >+ >+ short result; >+ unsigned char *commit_result = NULL; >+ >+ switch (ssm->cur_state) { >+ case SUBSM2_SEND_CONTROL: >+ async_write(ssm, vdev->control_packet, VFS_CONTROL_PACKET_SIZE); >+ break; >+ >+ case SUBSM2_RETURN_CODE: >+ async_read(ssm, 1, &result, sizeof(result)); >+ break; >+ >+ case SUBSM2_SEND_COMMIT: >+ /* next_receive_* packets could be sent only in pair */ >+ if (vdev->control_packet == next_receive_1) { >+ vdev->control_packet = next_receive_2; >+ fpi_ssm_jump_to_state(ssm, SUBSM2_SEND_CONTROL); >+ break; >+ } >+ /* commit_out in Windows differs in each commit, but I send the same each time */ >+ async_write(ssm, commit_out, sizeof(commit_out)); >+ break; >+ >+ case SUBSM2_COMMIT_RESPONSE: >+ commit_result = g_malloc(VFS_COMMIT_RESPONSE_SIZE); >+ async_read(ssm, 1, commit_result, VFS_COMMIT_RESPONSE_SIZE); >+ break; >+ >+ case SUBSM2_READ_EMPTY_INTERRUPT: >+ /* I don't know how to check result, it could be different */ >+ g_free(commit_result); >+ >+ async_read(ssm, 3, vdev->interrupt, VFS_INTERRUPT_SIZE); >+ break; >+ >+ case SUBSM2_ABORT_3: >+ /* Check that interrupt is empty */ >+ if (memcmp >+ (vdev->interrupt, empty_interrupt, VFS_INTERRUPT_SIZE)) { >+ fp_err("Unknown SUBSM2 state"); >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ break; >+ } >+ async_abort(ssm, 3); >+ break; >+ >+ case SUBSM2_CLEAR_EP2: >+ /* After turn_on Windows doesn't clear EP2 */ >+ if (vdev->control_packet != turn_on) >+ clear_ep2(ssm); >+ else >+ fpi_ssm_next_state(ssm); >+ break; >+ >+ default: >+ fp_err("Unknown SUBSM2 state"); >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ } >+} >+ >+/* Send device state control packet */ >+static void send_control_packet(struct fpi_ssm *ssm) >+{ >+ struct fp_img_dev *idev = ssm->priv; >+ >+ struct fpi_ssm *subsm = >+ fpi_ssm_new(idev->dev, send_control_packet_ssm, SUBSM2_STATES); >+ subsm->priv = idev; >+ fpi_ssm_start_subsm(ssm, subsm); >+} >+ >+/* Clears all fprint data */ >+static void clear_data(struct vfs_dev_t *vdev) >+{ >+ if (vdev->data != NULL) >+ g_free(vdev->data); >+ vdev->data = NULL; >+ vdev->memory = vdev->bytes = 0; >+} >+ >+#define VFS_NOISE_THRESHOLD 50 >+ >+/* Processes image before submitting. This function needs to be improved */ >+static void prepare_image(struct fp_img *img, struct vfs_line *data) >+{ >+ /* TODO: clean other falanges from print */ >+ >+ /* Noise cleaning. IMHO, it works pretty well >+ I've not detected cases when it doesn't work or cuts a part of the finger >+ Noise arises at the end of scan when some water remains on the scanner */ >+ while (img->height > 0) { >+ int val1 = data[img->height - 1].noise_hash_1; >+ int val2 = data[img->height - 1].noise_hash_2; >+ if (val1 > VFS_NOISE_THRESHOLD >+ && val1 < 256 - VFS_NOISE_THRESHOLD >+ && val2 > VFS_NOISE_THRESHOLD >+ && val2 < 256 - VFS_NOISE_THRESHOLD) >+ break; >+ --img->height; >+ } >+ fpi_img_resize(img, img->width * img->height); >+ >+ /* If image is not good enough */ >+ if (img->height < img->width) { >+ img->height = img->width; >+ fpi_img_resize(img, img->width * img->height); >+ memset(img->data, 0, img->width * img->height); >+ return; >+ } >+ >+ /* Pixman downscaling(too big images are processed slow or cause segfault during minutae detection) >+ TODO: make scaling uniform using timeline data from last eight bytes */ >+ >+ if (img->height > VFS_MAX_HEIGHT) >+ fpi_im_downscale(img, 1.0, >+ (double)VFS_MAX_HEIGHT / img->height); >+} >+ >+/* Creates image from raw scanner data */ >+static struct fp_img *get_raw_image(struct vfs_dev_t *vdev) >+{ >+ struct vfs_line *data = (struct vfs_line *)vdev->data; >+ int height = vdev->bytes / VFS_IMAGE_WIDTH; >+ int width = VFS_RESULT_IMAGE_WIDTH; >+ >+ struct fp_img *img = fpi_img_new(width * height); >+ img->width = width, img->height = height; >+ img->flags = FP_IMG_V_FLIPPED; >+ for (int x = 0; x < height; ++x) >+ memcpy(img->data + x * width, data[x].data, width); >+ >+ return img; >+} >+ >+/* Processes and submits image after fingerprint received */ >+static void submit_image(struct fp_img_dev *idev) >+{ >+ struct vfs_dev_t *vdev = idev->priv; >+ >+ /* We were not asked to submit image actually */ >+ if (!vdev->active) >+ return; >+ >+ struct fp_img *img = get_raw_image(vdev); >+ prepare_image(img, (struct vfs_line *)vdev->data); >+ >+ fpi_imgdev_image_captured(idev, img); >+ >+ /* Finger not on the scanner */ >+ fpi_imgdev_report_finger_status(idev, 0); >+} >+ >+/* After receiving interrupt from EP3 */ >+static void interrupt_callback(struct libusb_transfer *transfer) >+{ >+ struct fpi_ssm *ssm = transfer->user_data; >+ struct fp_img_dev *idev = ssm->priv; >+ struct vfs_dev_t *vdev = idev->priv; >+ >+ char *interrupt = vdev->interrupt; >+ int error = transfer->status, transferred = transfer->actual_length; >+ >+ libusb_free_transfer(transfer); >+ >+ vdev->wait_interrupt = 0; >+ >+ /* When we have cancelled transfer, error is ok actually */ >+ if (!vdev->active && error == LIBUSB_TRANSFER_CANCELLED) >+ return; >+ >+ if (error != 0) { >+ fp_err("USB read interrupt transfer: %s", >+ libusb_error_name(error)); >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ return; >+ } >+ >+ /* Interrupt size is VFS_INTERRUPT_SIZE bytes in all known cases */ >+ if (transferred != VFS_INTERRUPT_SIZE) { >+ fp_err("Unknown interrupt size %d", transferred); >+ libusb_free_transfer(transfer); >+ /* Abort ssm */ >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ return; >+ } >+ >+ if (memcmp(interrupt, interrupt2, VFS_INTERRUPT_SIZE) == 0) { >+ /* Go to the next ssm stage */ >+ fpi_ssm_next_state(ssm); >+ return; >+ } >+ >+ if (memcmp(interrupt, interrupt3, VFS_INTERRUPT_SIZE) == 0) { >+ /* Go to the next ssm stage */ >+ fpi_ssm_next_state(ssm); >+ return; >+ } >+ >+ /* Standard interrupt */ >+ if (memcmp(interrupt, interrupt1, VFS_INTERRUPT_SIZE) == 0) { >+ /* Go to the next ssm stage */ >+ fpi_ssm_next_state(ssm); >+ return; >+ } >+ >+ /* When finger is on the scanner before turn_on */ >+ if (interrupt[0] == 0x01) { >+ fp_warn("Finger is already on the scanner"); >+ >+ /* Go to the next ssm stage */ >+ fpi_ssm_next_state(ssm); >+ return; >+ } >+ >+ /* TODO: handle all interrupts */ >+ fp_err("Unknown interrupt '%02x:%02x:%02x:%02x:%02x'!", >+ interrupt[0] & 0xff, interrupt[1] & 0xff, interrupt[2] & 0xff, >+ interrupt[3] & 0xff, interrupt[4] & 0xff); >+ >+ /* Abort ssm */ >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+} >+ >+static void receive_callback(struct libusb_transfer *transfer) >+{ >+ struct fpi_ssm *ssm = transfer->user_data; >+ struct fp_img_dev *idev = ssm->priv; >+ struct vfs_dev_t *vdev = idev->priv; >+ >+ int transferred = transfer->actual_length, error = transfer->status; >+ >+ libusb_free_transfer(transfer); >+ >+ if (error != 0 && error != LIBUSB_TRANSFER_TIMED_OUT) { >+ fp_err("USB read transfer: %s", libusb_error_name(error)); >+ >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ return; >+ } >+ >+ /* Check if fingerprint data is over */ >+ if (transferred == 0) >+ fpi_ssm_next_state(ssm); >+ else { >+ /* We need more data */ >+ vdev->bytes += transferred; >+ fpi_ssm_jump_to_state(ssm, ssm->cur_state); >+ } >+} >+ >+/* Stub to keep SSM alive when waiting an interrupt */ >+static void wait_interrupt(void *data) >+{ >+ struct fpi_ssm *ssm = data; >+ struct fp_img_dev *idev = ssm->priv; >+ struct vfs_dev_t *vdev = idev->priv; >+ >+ /* Keep sleeping while this flag is on */ >+ if (vdev->wait_interrupt) >+ fpi_ssm_jump_to_state(ssm, ssm->cur_state); >+} >+ >+/* SSM stub to prepare device to another scan after orange light was on */ >+static void another_scan(void *data) >+{ >+ struct fpi_ssm *ssm = data; >+ fpi_ssm_jump_to_state(ssm, SSM_TURN_ON); >+} >+ >+/* Another SSM stub to continue after waiting for probable vdev->active changes */ >+static void scan_completed(void *data) >+{ >+ struct fpi_ssm *ssm = data; >+ fpi_ssm_next_state(ssm); >+} >+ >+/* Main SSM loop */ >+static void activate_ssm(struct fpi_ssm *ssm) >+{ >+ struct fp_img_dev *idev = ssm->priv; >+ struct libusb_device_handle *udev = idev->udev; >+ struct vfs_dev_t *vdev = idev->priv; >+ >+ switch (ssm->cur_state) { >+ case SSM_INITIAL_ABORT_1: >+ async_abort(ssm, 1); >+ break; >+ >+ case SSM_INITIAL_ABORT_2: >+ async_abort(ssm, 2); >+ break; >+ >+ case SSM_INITIAL_ABORT_3: >+ async_abort(ssm, 3); >+ break; >+ >+ case SSM_CLEAR_EP2: >+ clear_ep2(ssm); >+ break; >+ >+ case SSM_TURN_OFF: >+ /* Set control_packet argument */ >+ vdev->control_packet = turn_off; >+ >+ send_control_packet(ssm); >+ break; >+ >+ case SSM_TURN_ON: >+ if (!vdev->active) { >+ /* The only correct exit */ >+ fpi_ssm_mark_completed(ssm); >+ >+ if (vdev->need_report) { >+ fpi_imgdev_deactivate_complete(idev); >+ vdev->need_report = 0; >+ } >+ break; >+ } >+ /* Set control_packet argument */ >+ vdev->control_packet = turn_on; >+ >+ send_control_packet(ssm); >+ break; >+ >+ case SSM_ASK_INTERRUPT: >+ /* Activated, light must be blinking now */ >+ >+ /* If we first time here, report that activate completed */ >+ if (vdev->need_report) { >+ fpi_imgdev_activate_complete(idev, 0); >+ vdev->need_report = 0; >+ } >+ >+ /* Asyncronously enquire an interrupt */ >+ vdev->transfer = libusb_alloc_transfer(0); >+ libusb_fill_interrupt_transfer(vdev->transfer, udev, 0x83, >+ vdev->interrupt, >+ VFS_INTERRUPT_SIZE, >+ interrupt_callback, ssm, 0); >+ libusb_submit_transfer(vdev->transfer); >+ >+ /* This flag could be turned off only in callback function */ >+ vdev->wait_interrupt = 1; >+ >+ /* I've put it here to be sure that data is cleared */ >+ clear_data(vdev); >+ >+ fpi_ssm_next_state(ssm); >+ break; >+ >+ case SSM_WAIT_INTERRUPT: >+ /* Check if user had interrupted the process */ >+ if (!vdev->active) { >+ libusb_cancel_transfer(vdev->transfer); >+ fpi_ssm_jump_to_state(ssm, SSM_CLEAR_EP2); >+ break; >+ } >+ >+ if (vdev->wait_interrupt) >+ fpi_timeout_add(VFS_SSM_TIMEOUT, wait_interrupt, ssm); >+ break; >+ >+ case SSM_RECEIVE_FINGER: >+ if (vdev->memory == 0) { >+ /* Initialize fingerprint buffer */ >+ if (vdev->data != NULL) >+ g_free(vdev->data); >+ vdev->memory = VFS_USB_BUFFER_SIZE; >+ vdev->data = g_malloc(vdev->memory); >+ vdev->bytes = 0; >+ >+ /* Finger is on the scanner */ >+ fpi_imgdev_report_finger_status(idev, 1); >+ } >+ >+ /* Increase buffer size while it's insufficient */ >+ while (vdev->bytes + VFS_USB_BUFFER_SIZE > vdev->memory) { >+ vdev->memory <<= 1; >+ vdev->data = >+ (unsigned char *)g_realloc(vdev->data, >+ vdev->memory); >+ } >+ >+ /* Receive chunk of data */ >+ vdev->transfer = libusb_alloc_transfer(0); >+ libusb_fill_bulk_transfer(vdev->transfer, udev, 0x82, >+ vdev->data + vdev->bytes, >+ VFS_USB_BUFFER_SIZE, receive_callback, >+ ssm, VFS_USB_TIMEOUT); >+ libusb_submit_transfer(vdev->transfer); >+ break; >+ >+ case SSM_SUBMIT_IMAGE: >+ submit_image(idev); >+ clear_data(vdev); >+ >+ /* Wait for probable vdev->active changing */ >+ fpi_timeout_add(VFS_SSM_TIMEOUT, scan_completed, ssm); >+ break; >+ >+ case SSM_NEXT_RECEIVE: >+ if (!vdev->active) { >+ /* It's the last scan */ >+ fpi_ssm_jump_to_state(ssm, SSM_CLEAR_EP2); >+ break; >+ } >+ >+ /* Set control_packet argument */ >+ vdev->control_packet = next_receive_1; >+ >+ send_control_packet(ssm); >+ break; >+ >+ case SSM_WAIT_ANOTHER_SCAN: >+ /* Orange light is on now */ >+ fpi_timeout_add(VFS_SSM_ORANGE_TIMEOUT, another_scan, ssm); >+ break; >+ >+ default: >+ fp_err("Unknown state"); >+ fpi_imgdev_session_error(idev, -EIO); >+ fpi_ssm_mark_aborted(ssm, -EIO); >+ } >+} >+ >+/* Driver functions */ >+ >+/* Activate device */ >+static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state) >+{ >+ struct vfs_dev_t *vdev = idev->priv; >+ >+ /* Initialize flags */ >+ vdev->active = 1; >+ vdev->need_report = 1; >+ >+ struct fpi_ssm *ssm = fpi_ssm_new(idev->dev, activate_ssm, SSM_STATES); >+ ssm->priv = idev; >+ fpi_ssm_start(ssm, fpi_ssm_free); >+ return 0; >+} >+ >+/* Deactivate device */ >+static void dev_deactivate(struct fp_img_dev *idev) >+{ >+ struct vfs_dev_t *vdev = idev->priv; >+ >+ /* Initialize flags */ >+ vdev->active = 0; >+ vdev->need_report = 1; >+} >+ >+/* Callback for dev_open ssm */ >+static void dev_open_callback(struct fpi_ssm *ssm) >+{ >+ /* Notify open complete */ >+ fpi_imgdev_open_complete((struct fp_img_dev *)ssm->priv, 0); >+ fpi_ssm_free(ssm); >+} >+ >+/* Open device */ >+static int dev_open(struct fp_img_dev *idev, unsigned long driver_data) >+{ >+ /* Claim usb interface */ >+ int error = libusb_claim_interface(idev->udev, 0); >+ if (error < 0) { >+ /* Interface not claimed, return error */ >+ fp_err("could not claim interface 0"); >+ return error; >+ } >+ >+ /* Initialize private structure */ >+ struct vfs_dev_t *vdev = g_malloc0(sizeof(struct vfs_dev_t)); >+ idev->priv = vdev; >+ >+ /* Clearing previous device state */ >+ struct fpi_ssm *ssm = fpi_ssm_new(idev->dev, activate_ssm, SSM_STATES); >+ ssm->priv = idev; >+ fpi_ssm_start(ssm, dev_open_callback); >+ return 0; >+} >+ >+/* Close device */ >+static void dev_close(struct fp_img_dev *idev) >+{ >+ /* Release private structure */ >+ g_free(idev->priv); >+ >+ /* Release usb interface */ >+ libusb_release_interface(idev->udev, 0); >+ >+ /* Notify close complete */ >+ fpi_imgdev_close_complete(idev); >+} >+ >+/* Usb id table of device */ >+static const struct usb_id id_table[] = { >+ {.vendor = 0x138a,.product = 0x0050}, >+ {0, 0, 0,}, >+}; >+ >+/* Device driver definition */ >+struct fp_img_driver vfs0050_driver = { >+ /* Driver specification */ >+ .driver = { >+ .id = VFS0050_ID, >+ .name = FP_COMPONENT, >+ .full_name = "Validity VFS0050", >+ .id_table = id_table, >+ .scan_type = FP_SCAN_TYPE_SWIPE, >+ }, >+ >+ /* Image specification */ >+ .flags = 0, >+ .img_width = VFS_RESULT_IMAGE_WIDTH, >+ .img_height = -1, >+ .bz3_threshold = 24, >+ >+ /* Routine specification */ >+ .open = dev_open, >+ .close = dev_close, >+ .activate = dev_activate, >+ .deactivate = dev_deactivate, >+}; >diff --git a/libfprint/drivers/vfs0050.h b/libfprint/drivers/vfs0050.h >new file mode 100644 >index 0000000..cb5f786 >--- /dev/null >+++ b/libfprint/drivers/vfs0050.h >@@ -0,0 +1,374 @@ >+/* >+ * Validity VFS0050 driver for libfprint >+ * Copyright (C) 2015 Konstantin Semenov <zemen17@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 >+ */ >+ >+/* Timeout for all send/recv operations, except interrupt waiting and abort */ >+#define VFS_USB_TIMEOUT 100 >+/* Timeout for usb abort */ >+#define VFS_USB_ABORT_TIMEOUT 20 >+/* Default timeout for SSM timers */ >+#define VFS_SSM_TIMEOUT 100 >+/* Timeout for orange light */ >+#define VFS_SSM_ORANGE_TIMEOUT 700 >+ >+/* Buffer size for abort and fprint receiving */ >+#define VFS_USB_BUFFER_SIZE 65536 >+ >+/* Do not touch this parameters! */ >+ >+/* Width from scanner including extra data */ >+#define VFS_IMAGE_WIDTH 148 >+/* Only fprint image width from scanner */ >+#define VFS_RESULT_IMAGE_WIDTH 100 >+/* Maximum result image height */ >+#define VFS_MAX_HEIGHT 600 >+/* Size of control packets: turn_on, turn_off, next_receive_* */ >+#define VFS_CONTROL_PACKET_SIZE 125 >+/* Size of result of commit */ >+#define VFS_COMMIT_RESPONSE_SIZE 1106 >+/* Size of interrupt from EP3 */ >+#define VFS_INTERRUPT_SIZE 5 >+ >+/* Fingerprint horizontal line */ >+struct vfs_line { >+ /* It must be always 0x01 */ >+ unsigned char _0x01; >+ /* It must be always 0xfe */ >+ unsigned char _0xfe; >+ >+ /* line number starting from some number in Little-Endian */ >+ unsigned short id; >+ >+ /* Some hashes which are useful to detect noise */ >+ unsigned char noise_hash_1; >+ unsigned char noise_hash_2; >+ >+ /* The first byte of _somedata is always 0x00, the second is strange useless cyclic line number */ >+ unsigned short _somedata; >+ >+ /* Fingerprint image */ >+ unsigned char data[VFS_RESULT_IMAGE_WIDTH]; >+ >+ /* Narrow fingerprint part from the center, diagonally, currently it's skipped */ >+ unsigned char extra[32]; >+ >+ /* scan_data is 0xfb except some rare cases, it seems that it's timeline but currently it's skipped too */ >+ unsigned char scan_data[8]; >+} __attribute__ ((__packed__)); >+ >+/* The main driver structure */ >+struct vfs_dev_t { >+ /* One if we were asked to read fingerprint, zero otherwise */ >+ char active; >+ >+ /* Control packet parameter for send_control_packet */ >+ unsigned char *control_packet; >+ >+ /* Current async transfer */ >+ struct libusb_transfer *transfer; >+ >+ /* Should we call fpi_imgdev_activate_complete or fpi_imgdev_deactivate_complete */ >+ char need_report; >+ >+ /* Should we wait more for interrupt */ >+ char wait_interrupt; >+ >+ /* Received fingerprint data */ >+ unsigned char *data; >+ >+ /* Current number of received bytes and current memory used by data */ >+ int bytes, memory; >+ >+ /* Received interrupt data */ >+ unsigned char interrupt[8]; >+}; >+ >+/* SSM states for clear_ep2 */ >+enum SUBSM1 { >+ SUBSM1_COMMAND_04, >+ SUBSM1_RETURN_CODE, >+ SUBSM1_ABORT_2, >+ >+ SUBSM1_STATES, >+}; >+ >+/* SSM states for control */ >+enum SUBSM2 { >+ SUBSM2_SEND_CONTROL, >+ SUBSM2_RETURN_CODE, /* If next_receive, send another control packet */ >+ >+ SUBSM2_SEND_COMMIT, >+ SUBSM2_COMMIT_RESPONSE, >+ SUBSM2_READ_EMPTY_INTERRUPT, >+ SUBSM2_ABORT_3, >+ SUBSM2_CLEAR_EP2, >+ >+ SUBSM2_STATES, >+}; >+ >+/* SSM states for activate_ssm */ >+enum SSM_STATE { >+ SSM_INITIAL_ABORT_1, >+ SSM_INITIAL_ABORT_2, >+ SSM_INITIAL_ABORT_3, >+ SSM_CLEAR_EP2, >+ SSM_TURN_OFF, >+ >+ /* Here the device is turned off; if not active, complete ssm */ >+ SSM_TURN_ON, >+ >+ SSM_ASK_INTERRUPT, >+ SSM_WAIT_INTERRUPT, >+ >+ SSM_RECEIVE_FINGER, >+ SSM_SUBMIT_IMAGE, >+ >+ /* If not active, jump to CLEAR_EP2 */ >+ SSM_NEXT_RECEIVE, >+ SSM_WAIT_ANOTHER_SCAN, >+ /* Jump to TURN_ON */ >+ >+ SSM_STATES >+}; >+ >+/* Blocks of data from USB sniffer */ >+ >+/* Turns on the light */ >+static unsigned char turn_on[] = { >+ 0x39, 0x20, 0xBF, 0x02, 0x00, 0xF4, 0x01, 0x00, 0x00, 0x01, 0xD1, 0x00, >+ 0x20, 0xD1, 0xD1, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x01, 0x00, >+ 0x00, 0x01, 0x00, 0x00, >+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0xF4, 0x01, 0x00, >+ 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0xF4, 0x01, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 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, 0x00, 0x00, 0x00, >+ 0x00, >+}; >+ >+/* Power off */ >+static unsigned char turn_off[] = { >+ 0x39, 0x01, 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, 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, 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, >+}; >+ >+/* Turns on orange light */ >+static unsigned char next_receive_1[] = { >+ 0x39, 0xB8, 0x0B, 0x00, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x01, 0xD1, 0x00, >+ 0x20, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x01, 0x00, 0x00, >+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 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, 0x00, 0x00, 0x00, >+ 0x00, >+}; >+ >+/* Packet directly after next_receive_1 */ >+static unsigned char next_receive_2[] = { >+ 0x39, 0xE8, 0x03, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x01, 0xD1, 0x00, >+ 0x20, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x01, 0x00, 0x00, >+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0xE8, 0x03, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 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, 0x00, 0x00, 0x00, >+ 0x00, >+}; >+ >+/* Commit message */ >+static unsigned char commit_out[] = { >+ 0x02, 0x94, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x2C, 0x03, 0x00, >+ 0x30, 0x1B, 0x00, 0x00, >+ 0x00, 0x20, 0x00, 0x08, 0x00, 0x20, 0x03, 0x00, 0x30, 0x3D, 0x10, 0x00, >+ 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x18, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x24, 0x03, 0x00, >+ 0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x28, 0x03, 0x00, >+ 0x30, 0x08, 0x00, 0x00, >+ 0x00, 0x20, 0x00, 0x08, 0x00, 0x30, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, >+ 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x38, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x3C, 0x03, 0x00, >+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x44, 0x03, 0x00, >+ 0x30, 0x14, 0x00, 0x00, >+ 0x00, 0x20, 0x00, 0x08, 0x00, 0x48, 0x03, 0x00, 0x30, 0x01, 0x04, 0x02, >+ 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x4C, 0x03, 0x00, 0x30, 0x01, 0x0C, 0x02, 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x54, 0x03, 0x00, >+ 0x30, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x5C, 0x03, 0x00, >+ 0x30, 0x90, 0x01, 0x02, >+ 0x00, 0x20, 0x00, 0x08, 0x00, 0x60, 0x03, 0x00, 0x30, 0x2C, 0x01, 0x19, >+ 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x64, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x6C, 0x03, 0x00, >+ 0x30, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x70, 0x03, 0x00, >+ 0x30, 0x21, 0x80, 0x00, >+ 0x00, 0x20, 0x00, 0x08, 0x00, 0x78, 0x03, 0x00, 0x30, 0x09, 0x00, 0x02, >+ 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x7C, 0x03, 0x00, 0x30, 0x0B, 0x00, 0x19, 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x80, 0x03, 0x00, >+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x84, 0x03, 0x00, >+ 0x30, 0x3A, 0x00, 0x00, >+ 0x00, 0x20, 0x00, 0x08, 0x00, 0x88, 0x03, 0x00, 0x30, 0x14, 0x00, 0x00, >+ 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x8C, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x90, 0x03, 0x00, >+ 0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x94, 0x03, 0x00, >+ 0x30, 0x08, 0x00, 0x00, >+ 0x00, 0x20, 0x00, 0x08, 0x00, 0x98, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1, >+ 0x01, 0x20, 0x00, 0x08, >+ 0x00, 0x9C, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1, 0x01, 0x20, 0x00, 0x08, >+ 0x00, 0xA8, 0x03, 0x00, >+ 0x30, 0x64, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xAC, 0x03, 0x00, >+ 0x30, 0x64, 0x01, 0x00, >+ 0x00, 0x20, 0x00, 0x08, 0x00, 0xB0, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00, >+ 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0xB4, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0xB8, 0x03, 0x00, >+ 0x30, 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xBC, 0x03, 0x00, >+ 0x30, 0x05, 0x00, 0x00, >+ 0x00, 0x20, 0x00, 0x08, 0x00, 0xC0, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, >+ 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x84, 0x03, 0x00, 0x30, 0x3B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x08, 0x07, 0x00, >+ 0x30, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x0C, 0x07, 0x00, >+ 0x30, 0x00, 0x00, 0x00, >+ 0x00, 0x20, 0x00, 0x08, 0x00, 0x14, 0x07, 0x00, 0x30, 0x20, 0x00, 0x00, >+ 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x1C, 0x07, 0x00, 0x30, 0x1A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x70, 0x0D, 0x00, >+ 0x30, 0x01, 0x00, 0x00, 0x00, 0x25, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x20, 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, 0x02, 0x00, 0x90, 0x00, 0x00, 0x00, 0x2B, 0xFF, 0x2B, 0xFF, 0x2B, >+ 0xED, 0x00, 0x00, 0x2B, >+ 0xFB, 0x00, 0x00, 0x2B, 0xC5, 0x00, 0x00, 0x2B, 0x05, 0x80, 0x70, 0x00, >+ 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x24, 0xD3, 0x2E, 0xC0, 0x2C, 0x3B, 0x08, 0xF0, 0x3B, 0x09, 0x24, >+ 0xBB, 0x3B, 0x0B, 0x24, >+ 0xAA, 0x3B, 0x1F, 0xF8, 0x00, 0x3B, 0x3F, 0xF0, 0x00, 0x3B, 0x35, 0xC0, >+ 0x00, 0x38, 0x80, 0x2C, >+ 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x38, 0x80, 0x2C, 0x70, 0x00, >+ 0x00, 0x00, 0x00, 0xC0, >+ 0x3A, 0x80, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x3B, 0x0A, 0x80, >+ 0x2E, 0x83, 0x24, 0xDB, >+ 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x2C, 0x31, 0x83, 0x2C, 0x70, >+ 0x00, 0x00, 0x00, 0x00, >+ 0xCB, 0x33, 0x1B, 0x83, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xCB, 0x31, >+ 0x83, 0x2C, 0x70, 0x00, >+ 0x00, 0x00, 0x00, 0xCB, 0x00, 0x33, 0x1E, 0x83, 0x2E, 0x25, 0xFF, 0xC4, >+ 0x00, 0x2F, 0x06, 0x84, >+ 0x2E, 0x00, 0x00, 0x10, 0x20, 0x29, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, >+ 0x00, 0x23, 0x00, 0x00, >+ 0x00, 0x21, 0x00, 0x10, 0x00, 0x48, 0x03, 0x00, 0x30, 0xFF, 0xF0, 0xFF, >+ 0xFF, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x4C, 0x03, 0x00, >+ 0x30, 0xFF, 0xF0, 0xFF, >+ 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x21, 0x00, 0x10, >+ 0x00, 0x20, 0x03, 0x00, >+ 0x30, 0x7F, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, >+ 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x24, 0x03, 0x00, 0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x1C, 0x07, 0x00, >+ 0x30, 0x1A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x20, 0x03, 0x00, >+ 0x30, 0xC3, 0xFF, 0xFF, >+ 0xFF, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, >+ 0x00, 0x80, 0x03, 0x00, >+ 0x30, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x84, 0x00, 0x31, 0x65, 0x77, >+ 0x77, 0x77, 0x78, 0x88, >+ 0x77, 0x77, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x77, 0x67, >+ 0x66, 0x66, 0x66, 0x66, >+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x66, 0x66, 0x66, >+ 0x66, 0x77, 0x66, 0x66, >+ 0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x76, 0x66, 0x56, >+ 0x66, 0x66, 0x56, 0x55, >+ 0x65, 0x66, 0x66, 0x66, 0x65, 0x66, 0x66, 0x55, 0x66, 0x66, 0x65, 0x66, >+ 0x76, 0x76, 0x77, 0x77, >+ 0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x77, 0x67, 0x66, 0x66, 0x66, 0x56, >+ 0x65, 0x66, 0x65, 0x66, >+ 0x66, 0x55, 0x55, 0x54, 0x55, 0x65, 0x66, 0x66, 0x66, 0x76, 0x77, 0x87, >+ 0x88, 0x77, 0x66, 0x66, >+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x66, 0x55, 0x55, 0x65, 0x56, 0x55, >+ 0x55, 0x55, 0x54, 0x45, >+ 0x54, 0x55, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, >+ 0x66, 0x26, 0x00, 0x28, >+ 0x00, 0xFF, 0x00, 0x0F, 0x00, 0xF0, 0xF0, 0x0F, 0x00, 0x20, 0x00, 0x00, >+ 0x00, 0x30, 0x01, 0x02, >+ 0x00, 0x2C, 0x01, 0x28, 0x00, 0x20, 0x80, 0x00, 0x00, 0x0A, 0x00, 0x02, >+ 0x00, 0x0B, 0x00, 0x19, >+ 0x00, 0x40, 0x1F, 0x10, 0x27, 0x00, 0x0F, 0x03, 0x00, >+}; >+ >+/* Known interrupts */ >+ >+static unsigned char empty_interrupt[] = { >+ 0x00, 0x00, 0x00, 0x00, 0x00, >+}; >+ >+static unsigned char interrupt1[] = { >+ 0x02, 0x00, 0x0E, 0x00, 0xF0, >+}; >+ >+static unsigned char interrupt2[] = { >+ 0x02, 0x04, 0x0A, 0x00, 0xF0, >+}; >+ >+static unsigned char interrupt3[] = { >+ 0x02, 0x00, 0x0A, 0x00, 0xF0, >+}; >diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h >index f640f58..fe3bfec 100644 >--- a/libfprint/fp_internal.h >+++ b/libfprint/fp_internal.h >@@ -305,6 +305,9 @@ extern struct fp_img_driver upektc_img_driver; > #ifdef ENABLE_ETES603 > extern struct fp_img_driver etes603_driver; > #endif >+#ifdef ENABLE_VFS0050 >+extern struct fp_img_driver vfs0050_driver; >+#endif > > extern libusb_context *fpi_usb_ctx; > extern GSList *opened_devices; >@@ -402,6 +405,7 @@ int fpi_img_compare_print_data(struct fp_print_data *enrolled_print, > int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print, > struct fp_print_data **gallery, int match_threshold, size_t *match_offset); > struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor); >+void fpi_im_downscale(struct fp_img *img, double w_factor, double h_factor); > > /* polling and timeouts */ > >diff --git a/libfprint/fprint-list-udev-rules.c b/libfprint/fprint-list-udev-rules.c >index 4b18f5a..7af8d54 100644 >--- a/libfprint/fprint-list-udev-rules.c >+++ b/libfprint/fprint-list-udev-rules.c >@@ -74,7 +74,8 @@ static void print_driver (struct fp_driver *driver) > if (num_printed == 0) > printf ("# %s\n", driver->full_name); > >- 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); >+ printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n, MODE=\"0666\"\n", driver->id_table[i].vendor, driver->id_table[i].product); >+ printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n", driver->id_table[i].vendor, driver->id_table[i].product, driver->full_name); > num_printed++; > } > >diff --git a/libfprint/imgdev.c b/libfprint/imgdev.c >index 3b5d3f3..7fc687a 100644 >--- a/libfprint/imgdev.c >+++ b/libfprint/imgdev.c >@@ -165,6 +165,15 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev, > case IMG_ACTION_VERIFY: > fpi_drvcb_report_verify_result(imgdev->dev, r, img); > fp_print_data_free(data); >+ >+ /* the callback can cancel verifying, so recheck current >+ * action and the status to see if retry is needed */ >+ if (imgdev->action == IMG_ACTION_VERIFY && >+ r > 0 && r != FP_VERIFY_MATCH && r != FP_VERIFY_NO_MATCH) { >+ imgdev->action_result = 0; >+ imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON; >+ dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON); >+ } > break; > case IMG_ACTION_IDENTIFY: > fpi_drvcb_report_identify_result(imgdev->dev, r, >diff --git a/libfprint/pixman.c b/libfprint/pixman.c >index 1b4ca06..e37abba 100644 >--- a/libfprint/pixman.c >+++ b/libfprint/pixman.c >@@ -61,3 +61,38 @@ struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned > return newimg; > } > >+void fpi_im_downscale(struct fp_img *img, double w_factor, double h_factor) >+{ >+ int new_width = img->width * w_factor; >+ int new_height = img->height * h_factor; >+ >+ pixman_image_t *orig, *resized; >+ pixman_transform_t transform; >+ >+ orig = pixman_image_create_bits(PIXMAN_a8, img->width, img->height, (uint32_t *)img->data, img->width); >+ resized = pixman_image_create_bits(PIXMAN_a8, new_width, new_height, NULL, new_width); >+ >+ pixman_transform_init_identity(&transform); >+ pixman_transform_scale(NULL, &transform, pixman_double_to_fixed(w_factor), pixman_double_to_fixed(h_factor)); >+ pixman_image_set_transform(orig, &transform); >+ pixman_image_set_filter(orig, PIXMAN_FILTER_BEST, NULL, 0); >+ pixman_image_composite32(PIXMAN_OP_SRC, >+ orig, /* src */ >+ NULL, /* mask */ >+ resized, /* dst */ >+ 0, 0, /* src x y */ >+ 0, 0, /* mask x y */ >+ 0, 0, /* dst x y */ >+ new_width, new_height /* width height */ >+ ); >+ >+ fpi_img_resize(img, new_width * new_height); >+ img->width = new_width; >+ img->height = new_height; >+ >+ memcpy(img->data, pixman_image_get_data(resized), new_width * new_height); >+ >+ pixman_image_unref(orig); >+ pixman_image_unref(resized); >+} >+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 531698
:
390940
|
390944
| 408804 |
408806