Hi Kunal,
the program on example directory (like fprint_demo and pam_fprint)
receive the result and re-call the action if not completed.
The daemon fprintd (and fprintd-verify) when receive "remove finger"
result wait for another image without re-call the action.
Try the new patch. It seem to work with all these program.
Bye
Sergio
Il giorno mer, 02/03/2011 alle 17.13 +0530, Kunal Gangakhedkar ha
scritto:
> On Wednesday 02 Mar 2011 2:38:40 pm Sergio Cerlesi wrote:
> > Hi Kunal,
> >
> > thank for logs. I found and successful reproduced the second issue.
> >
> > Seem to be a bug of driver that appear when it are called from a program
> > that not handle "remove finger" result like fprint_demo or pam_fprint.
> > With fprintd and pam_fprintd the bug are not present.
> >
>
> I wasn't using either of these programs.
> I was using the ones under libfprint/examples - enroll and verify.
>
> These seem to handle the 'remove finger' result because they show the message
> like 'Please remove finger from sensor'.
> For example, this is the code from libfprint/examples/enroll.c (line 83):
>
> case FP_ENROLL_RETRY_REMOVE_FINGER:
> printf("Scan failed, please remove your finger and then try "
> "again.\n");
> break;
>
> So, it seems to handle it.. :)
>
> Kunal
>
> > I will fix the driver.
> >
> > Bye
> > Sergio
> >
--- ./libfprint/drivers/vfs101.c.orig 2011-01-20 14:00:52.535502073 +0100
+++ ./libfprint/drivers/vfs101.c 2011-03-02 11:50:11.340482661 +0100
@@ -0,0 +1,1327 @@
+/*
+ * Validity VFS101 driver for libfprint
+ * Copyright (C) 2011 Sergio Cerlesi <[email protected]>
+ *
+ * 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 <string.h>
+
+#define FP_COMPONENT "vfs101"
+
+#include <fp_internal.h>
+
+/* Input-Output usb endpoint */
+#define EP_IN(n) (n | LIBUSB_ENDPOINT_IN)
+#define EP_OUT(n) (n | LIBUSB_ENDPOINT_OUT)
+
+/* Usb bulk timeout */
+#define BULK_TIMEOUT 100
+
+/* The device send back the image into block of 16 frames of 292 bytes */
+#define VFS_FRAME_SIZE 292
+#define VFS_BLOCK_SIZE 16 * VFS_FRAME_SIZE
+
+/* Image width */
+#define VFS_IMG_WIDTH 200
+
+/* Maximum image height */
+#define VFS_IMG_MAX_HEIGHT 5000
+
+/* Minimum image height */
+#define VFS_IMG_MIN_HEIGHT 200
+
+/* Maximum image size */
+#define VFS_IMG_MAX_SIZE (VFS_IMG_MAX_HEIGHT * VFS_FRAME_SIZE)
+
+/* Scan level thresold */
+#define VFS_IMG_SLT_BEGIN 768
+#define VFS_IMG_SLT_END 256
+#define VFS_IMG_SLT_LINES 10
+
+/* Minimum image level */
+#define VFS_IMG_MIN_IMAGE_LEVEL 144
+
+/* Number of enroll stages */
+#define VFS_NR_ENROLL 3
+
+/* Device parameters address */
+#define VFS_PAR_000E 0x000e
+#define VFS_PAR_0011 0x0011
+#define VFS_PAR_THRESHOLD 0x0057
+#define VFS_PAR_STATE_3 0x005e
+#define VFS_PAR_STATE_5 0x005f
+#define VFS_PAR_INFO_RATE 0x0062
+#define VFS_PAR_0076 0x0076
+#define VFS_PAR_INFO_CONTRAST 0x0077
+#define VFS_PAR_0078 0x0078
+
+/* Device regiones address */
+#define VFS_REG_IMG_EXPOSURE 0xff500e
+#define VFS_REG_IMG_CONTRAST 0xff5038
+
+/* Device settings */
+#define VFS_VAL_000E 0x0001
+#define VFS_VAL_0011 0x0008
+#define VFS_VAL_THRESHOLD 0x0096
+#define VFS_VAL_STATE_3 0x0064
+#define VFS_VAL_STATE_5 0x00c8
+#define VFS_VAL_INFO_RATE 0x0001
+#define VFS_VAL_0076 0x0012
+#define VFS_VAL_INFO_CONTRAST 0x000f
+#define VFS_VAL_0078 0x2230
+#define VFS_VAL_IMG_EXPOSURE 0x21c0
+#define VFS_VAL_IMG_CONTRAST 0x0014
+
+/* Structure for Validity device */
+struct vfs101_dev
+{
+ /* Action state */
+ int active;
+
+ /* Sequential number */
+ unsigned int seqnum;
+
+ /* Usb transfer */
+ struct libusb_transfer *transfer;
+
+ /* Buffer for input/output */
+ unsigned char buffer[VFS_IMG_MAX_SIZE];
+
+ /* Length of data to send or received */
+ unsigned int length;
+
+ /* Ignore usb error */
+ int ignore_error;
+
+ /* Timeout */
+ struct fpi_timeout *timeout;
+
+ /* Number of enroll stage */
+ int enroll_stage;
+
+ /* Bottom line of image */
+ int bottom;
+
+ /* Top line of image */
+ int top;
+};
+
+/* Return byte at specified position */
+static inline unsigned char byte(int position, int value)
+{
+ return (value >> (position * 8)) & 0xff;
+}
+
+/* Return sequential number */
+static inline unsigned short get_seqnum(int h, int l)
+{
+ return (h<<8) | l;
+}
+
+/* Check sequential number */
+static inline int check_seqnum(struct vfs101_dev *vdev)
+{
+ if ((byte(0, vdev->seqnum) == vdev->buffer[0]) &&
+ (byte(1, vdev->seqnum) == vdev->buffer[1]))
+ return 0;
+ else
+ return 1;
+}
+
+/* Internal result codes */
+enum
+{
+ RESULT_RETRY,
+ RESULT_RETRY_SHORT,
+ RESULT_RETRY_REMOVE,
+ RESULT_COUNT,
+};
+
+/* Enroll result codes */
+static int result_codes[2][RESULT_COUNT] =
+{
+ {
+ FP_ENROLL_RETRY,
+ FP_ENROLL_RETRY_TOO_SHORT,
+ FP_ENROLL_RETRY_REMOVE_FINGER,
+ },
+ {
+ FP_VERIFY_RETRY,
+ FP_VERIFY_RETRY_TOO_SHORT,
+ FP_VERIFY_RETRY_REMOVE_FINGER,
+ },
+};
+
+/* Return result code based on current action */
+static int result_code(struct fp_img_dev *dev, int result)
+{
+ /* Check result value */
+ if (result < 0 && result >= RESULT_COUNT)
+ return result;
+
+ /* Return result code */
+ if (dev->action == IMG_ACTION_ENROLL)
+ return result_codes[0][result];
+ else
+ return result_codes[1][result];
+};
+
+/* Dump buffer for debug */
+#define dump_buffer(buf) \
+ fp_dbg("%02x %02x %02x %02x %02x %02x %02x %02x", \
+ buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13] \
+ )
+
+/* Callback of asynchronous send */
+static void async_send_cb(struct libusb_transfer *transfer)
+{
+ struct fpi_ssm *ssm = transfer->user_data;
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+
+ /* Cleanup transfer */
+ vdev->transfer = NULL;
+
+ /* Skip error check if ignore_error is set */
+ if (!vdev->ignore_error)
+ {
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
+ {
+ /* Transfer not completed, return IO error */
+ fp_err("transfer not completed, status = %d", transfer->status);
+ fpi_imgdev_session_error(dev, -EIO);
+ fpi_ssm_mark_aborted(ssm, -EIO);
+ goto out;
+ }
+
+ if (transfer->length != transfer->actual_length)
+ {
+ /* Data sended mismatch with expected, return protocol error */
+ fp_err("length mismatch, got %d, expected %d",
+ transfer->actual_length, transfer->length);
+ fpi_imgdev_session_error(dev, -EPROTO);
+ fpi_ssm_mark_aborted(ssm, -EPROTO);
+ goto out;
+ }
+ }
+ else
+ /* Reset ignore_error flag */
+ vdev->ignore_error = FALSE;
+
+ /* Dump buffer for debug */
+ dump_buffer(vdev->buffer);
+
+ fpi_ssm_next_state(ssm);
+
+out:
+ libusb_free_transfer(transfer);
+}
+
+/* Submit asynchronous send */
+static void async_send(struct fpi_ssm *ssm)
+{
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+ int r;
+
+ /* Allocation of transfer */
+ vdev->transfer = libusb_alloc_transfer(0);
+ if (!vdev->transfer)
+ {
+ /* Allocation transfer failed, return no memory error */
+ fp_err("allocation of usb transfer failed");
+ fpi_imgdev_session_error(dev, -ENOMEM);
+ fpi_ssm_mark_aborted(ssm, -ENOMEM);
+ return;
+ }
+
+ /* Put sequential number into the buffer */
+ vdev->seqnum++;
+ vdev->buffer[0] = byte(0, vdev->seqnum);
+ vdev->buffer[1] = byte(1, vdev->seqnum);
+
+ /* Prepare bulk transfer */
+ libusb_fill_bulk_transfer(vdev->transfer, dev->udev, EP_OUT(1), vdev->buffer, vdev->length, async_send_cb, ssm, BULK_TIMEOUT);
+
+ /* Submit transfer */
+ r = libusb_submit_transfer(vdev->transfer);
+ if (r != 0)
+ {
+ /* Submission of transfer failed, return IO error */
+ libusb_free_transfer(vdev->transfer);
+ fp_err("submit of usb transfer failed");
+ fpi_imgdev_session_error(dev, -EIO);
+ fpi_ssm_mark_aborted(ssm, -EIO);
+ return;
+ }
+}
+
+/* Callback of asynchronous recv */
+static void async_recv_cb(struct libusb_transfer *transfer)
+{
+ struct fpi_ssm *ssm = transfer->user_data;
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+
+ /* Cleanup transfer */
+ vdev->transfer = NULL;
+
+ /* Skip error check if ignore_error is set */
+ if (!vdev->ignore_error)
+ {
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
+ {
+ /* Transfer not completed, return IO error */
+ fp_err("transfer not completed, status = %d", transfer->status);
+ fpi_imgdev_session_error(dev, -EIO);
+ fpi_ssm_mark_aborted(ssm, -EIO);
+ goto out;
+ }
+
+ if (check_seqnum(vdev))
+ {
+ /* Sequential number received mismatch, return protocol error */
+ fp_err("seqnum mismatch, got %04x, expected %04x",
+ get_seqnum(vdev->buffer[1], vdev->buffer[0]), vdev->seqnum);
+ fpi_imgdev_session_error(dev, -EPROTO);
+ fpi_ssm_mark_aborted(ssm, -EPROTO);
+ goto out;
+ }
+ }
+ else
+ /* Reset ignore_error flag */
+ vdev->ignore_error = FALSE;
+
+ /* Dump buffer for debug */
+ dump_buffer(vdev->buffer);
+
+ /* Set length of received data */
+ vdev->length = transfer->actual_length;
+
+ fpi_ssm_next_state(ssm);
+
+out:
+ libusb_free_transfer(transfer);
+}
+
+/* Submit asynchronous recv */
+static void async_recv(struct fpi_ssm *ssm)
+{
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+ int r;
+
+ /* Allocation of transfer */
+ vdev->transfer = libusb_alloc_transfer(0);
+ if (!vdev->transfer)
+ {
+ /* Allocation transfer failed, return no memory error */
+ fp_err("allocation of usb transfer failed");
+ fpi_imgdev_session_error(dev, -ENOMEM);
+ fpi_ssm_mark_aborted(ssm, -ENOMEM);
+ return;
+ }
+
+ /* Prepare bulk transfer */
+ libusb_fill_bulk_transfer(vdev->transfer, dev->udev, EP_IN(1), vdev->buffer, 0x0f, async_recv_cb, ssm, BULK_TIMEOUT);
+
+ /* Submit transfer */
+ r = libusb_submit_transfer(vdev->transfer);
+ if (r != 0)
+ {
+ /* Submission of transfer failed, free transfer and return IO error */
+ libusb_free_transfer(vdev->transfer);
+ fp_err("submit of usb transfer failed");
+ fpi_imgdev_session_error(dev, -EIO);
+ fpi_ssm_mark_aborted(ssm, -EIO);
+ return;
+ }
+}
+
+static void async_load(struct fpi_ssm *ssm);
+
+/* Callback of asynchronous load */
+static void async_load_cb(struct libusb_transfer *transfer)
+{
+ struct fpi_ssm *ssm = transfer->user_data;
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+
+ /* Cleanup transfer */
+ vdev->transfer = NULL;
+
+ /* Skip error check if ignore_error is set */
+ if (!vdev->ignore_error)
+ {
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
+ {
+ /* Transfer not completed */
+ fp_err("transfer not completed, status = %d, length = %d", transfer->status, vdev->length);
+
+ if (vdev->length > 0)
+ {
+ /* Reset image length */
+ vdev->length = 0;
+
+ /* Return retry result */
+ fpi_imgdev_session_error(dev, result_code(dev, RESULT_RETRY));
+ fpi_ssm_next_state(ssm);
+ }
+ else
+ {
+ /* Return IO error */
+ fpi_imgdev_session_error(dev, -EIO);
+ fpi_ssm_mark_aborted(ssm, -EIO);
+ }
+ goto out;
+ }
+
+ if (transfer->actual_length % VFS_FRAME_SIZE)
+ {
+ /* Reset image length */
+ vdev->length = 0;
+
+ /* Received incomplete frame, return protocol error */
+ fp_err("received incomplete frame");
+ fpi_imgdev_session_error(dev, -EPROTO);
+ fpi_ssm_mark_aborted(ssm, -EPROTO);
+ goto out;
+ }
+
+ /* Increase image length */
+ vdev->length += transfer->actual_length;
+ }
+
+ if (transfer->actual_length == VFS_BLOCK_SIZE)
+ {
+ if ((VFS_IMG_MAX_SIZE - vdev->length) < VFS_BLOCK_SIZE)
+ {
+ /* Reset image length */
+ vdev->length = 0;
+
+ /* Buffer full, image too large, return no memory error */
+ fp_err("buffer full, image too large");
+ fpi_imgdev_session_error(dev, -ENOMEM);
+ fpi_ssm_mark_aborted(ssm, -ENOMEM);
+ goto out;
+ }
+ else
+ /* Image load not completed, submit another asynchronous load */
+ async_load(ssm);
+ }
+ else
+ {
+ /* Reset ignore_error flag */
+ if (vdev->ignore_error)
+ vdev->ignore_error = FALSE;
+
+ /* Image load completed, go to next state */
+ fp_dbg("image loaded, frames = %d", vdev->length / VFS_FRAME_SIZE);
+ fpi_ssm_next_state(ssm);
+ }
+
+out:
+ libusb_free_transfer(transfer);
+}
+
+/* Submit asynchronous load */
+static void async_load(struct fpi_ssm *ssm)
+{
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+ unsigned char *buffer;
+ int r;
+
+ /* Allocation of transfer */
+ vdev->transfer = libusb_alloc_transfer(0);
+ if (!vdev->transfer)
+ {
+ /* Allocation transfer failed, return no memory error */
+ fp_err("allocation of usb transfer failed");
+ fpi_imgdev_session_error(dev, -ENOMEM);
+ fpi_ssm_mark_aborted(ssm, -ENOMEM);
+ return;
+ }
+
+ /* Append new data into the buffer */
+ buffer = vdev->buffer + vdev->length;
+
+ /* Prepare bulk transfer */
+ libusb_fill_bulk_transfer(vdev->transfer, dev->udev, EP_IN(2), buffer, VFS_BLOCK_SIZE, async_load_cb, ssm, BULK_TIMEOUT);
+
+ /* Submit transfer */
+ r = libusb_submit_transfer(vdev->transfer);
+ if (r != 0)
+ {
+ /* Submission of transfer failed, return IO error */
+ libusb_free_transfer(vdev->transfer);
+ fp_err("submit of usb transfer failed");
+ fpi_imgdev_session_error(dev, -EIO);
+ fpi_ssm_mark_aborted(ssm, -EIO);
+ return;
+ }
+}
+
+/* Callback of asynchronous sleep */
+static void async_sleep_cb(void *data)
+{
+ struct fpi_ssm *ssm = data;
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+
+ /* Cleanup timeout */
+ vdev->timeout = NULL;
+
+ fpi_ssm_next_state(ssm);
+}
+
+/* Submit asynchronous sleep */
+static void async_sleep(unsigned int msec, struct fpi_ssm *ssm)
+{
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+
+ /* Add timeout */
+ vdev->timeout = fpi_timeout_add(msec, async_sleep_cb, ssm);
+
+ if (vdev->timeout == NULL)
+ {
+ /* Failed to add timeout */
+ fp_err("failed to add timeout");
+ fpi_imgdev_session_error(dev, -ETIME);
+ fpi_ssm_mark_aborted(ssm, -ETIME);
+ }
+}
+
+/* Swap ssm states */
+enum
+{
+ M_SWAP_SEND,
+ M_SWAP_RECV,
+ M_SWAP_NUM_STATES,
+};
+
+/* Exec swap sequential state machine */
+static void m_swap_state(struct fpi_ssm *ssm)
+{
+ switch (ssm->cur_state)
+ {
+ case M_SWAP_SEND:
+ /* Send data */
+ async_send(ssm);
+ break;
+
+ case M_SWAP_RECV:
+ /* Recv response */
+ async_recv(ssm);
+ break;
+ }
+}
+
+/* Start swap sequential state machine */
+static void m_swap(struct fpi_ssm *ssm, unsigned char *data, size_t length)
+{
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+ struct fpi_ssm *subsm;
+
+ /* Prepare data for sending */
+ memcpy(vdev->buffer, data, length);
+ memset(vdev->buffer + length, 0, 16 - length);
+ vdev->length = length;
+
+ /* Start swap ssm */
+ subsm = fpi_ssm_new(dev->dev, m_swap_state, M_SWAP_NUM_STATES);
+ subsm->priv = dev;
+ fpi_ssm_start_subsm(ssm, subsm);
+}
+
+/* Retrieve fingerprint image */
+static void vfs_get_print(struct fpi_ssm *ssm, unsigned int param, int type)
+{
+ unsigned char data[2][0x0e] = {
+ { 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01 },
+ { 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01 }
+ };
+
+ fp_dbg("param = %04x, type = %d", param, type);
+
+ /* Prepare data for sending */
+ data[type][6] = byte(0, param);
+ data[type][7] = byte(1, param);
+
+ /* Run swap sequential state machine */
+ m_swap(ssm, data[type], 0x0e);
+}
+
+/* Set a parameter value on the device */
+static void vfs_set_param(struct fpi_ssm *ssm, unsigned int param, unsigned int value)
+{
+ unsigned char data[0x0a] = { 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ fp_dbg("param = %04x, value = %04x", param, value);
+
+ /* Prepare data for sending */
+ data[6] = byte(0, param);
+ data[7] = byte(1, param);
+ data[8] = byte(0, value);
+ data[9] = byte(1, value);
+
+ /* Run swap sequential state machine */
+ m_swap(ssm, data, 0x0a);
+}
+
+/* Abort previous print */
+static void vfs_abort_print(struct fpi_ssm *ssm)
+{
+ unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00 };
+
+ fp_dbg("");
+
+ /* Run swap sequential state machine */
+ m_swap (ssm, data, 0x06);
+}
+
+/* Poke a value on a region */
+static void vfs_poke(struct fpi_ssm *ssm, unsigned int addr, unsigned int value, unsigned int size)
+{
+ unsigned char data[0x0f] = { 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ fp_dbg("addr = %04x, value = %04x", addr, value);
+
+ /* Prepare data for sending */
+ data[6] = byte(0, addr);
+ data[7] = byte(1, addr);
+ data[8] = byte(2, addr);
+ data[9] = byte(3, addr);
+ data[10] = byte(0, value);
+ data[11] = byte(1, value);
+ data[12] = byte(2, value);
+ data[13] = byte(3, value);
+ data[14] = byte(0, size);
+
+ /* Run swap sequential state machine */
+ m_swap(ssm, data, 0x0f);
+}
+
+/* Get current finger state */
+static void vfs_get_finger_state(struct fpi_ssm *ssm)
+{
+ unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x16, 0x00 };
+
+ fp_dbg("");
+
+ /* Run swap sequential state machine */
+ m_swap (ssm, data, 0x06);
+}
+
+/* Load raw image from reader */
+static void img_load(struct fpi_ssm *ssm)
+{
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+
+ fp_dbg("");
+
+ /* Reset image length */
+ vdev->length = 0;
+
+ /* Asynchronous load */
+ async_load(ssm);
+}
+
+/* Check if action is completed */
+static int action_completed(struct fp_img_dev *dev)
+{
+ struct vfs101_dev *vdev = dev->priv;
+
+ if ((dev->action == IMG_ACTION_ENROLL) &&
+ (vdev->enroll_stage < VFS_NR_ENROLL))
+ /* Enroll not completed, return false */
+ return FALSE;
+
+ else if (vdev->enroll_stage < 1)
+ /* Action not completed, return false */
+ return FALSE;
+
+ /* Action completed, return true */
+ return TRUE;
+}
+
+#define offset(x, y) ((x) + ((y) * VFS_FRAME_SIZE))
+
+/* Screen image to remove noise and find top and bottom line */
+static void img_screen(struct vfs101_dev *vdev)
+{
+ int y, x, count;
+ long int level;
+ int last_line = (vdev->length / VFS_FRAME_SIZE) - 1;
+
+ /* Set top and bottom line of image */
+ vdev->top = last_line;
+ vdev->bottom = 0;
+
+ fp_dbg("image height before screen = %d", vdev->top + 1);
+
+ count = 0;
+
+ /* Image returned from sensor can contain many empty lines,
+ * for remove these lines compare byte 282-283 (scan level information)
+ * with two differents threshold, one for the begin of finger image and
+ * one for the end. To increase stability of the code use a counter
+ * of lines that satisfy the threshold.
+ */
+ for (y = last_line; y >= 0; y--)
+ {
+ /* Take image scan level */
+ level = vdev->buffer[offset(283, y)] * 256 +
+ vdev->buffer[offset(282, y)];
+
+ if (level >= VFS_IMG_SLT_BEGIN && vdev->top == last_line)
+ {
+ /* Begin threshold satisfied */
+ if (count < VFS_IMG_SLT_LINES)
+ /* Increase count */
+ count++;
+ else
+ {
+ /* Found top fingerprint line */
+ vdev->top = y + VFS_IMG_SLT_LINES;
+ count = 0;
+ }
+ }
+ else if (level < VFS_IMG_SLT_END && vdev->top != last_line)
+ {
+ /* End threshold satisfied */
+ if (count < VFS_IMG_SLT_LINES)
+ /* Increase count */
+ count++;
+ else
+ {
+ /* Found bottom fingerprint line */
+ vdev->bottom = y + VFS_IMG_SLT_LINES;
+ break;
+ }
+ }
+ else
+ /* Not threshold satisfied, reset count */
+ count = 0;
+ }
+
+ fp_dbg("image height after screen = %d", vdev->top - vdev->bottom + 1);
+
+ /* Scan image and remove noise */
+ for (y = vdev->bottom; y <= vdev->top; y++)
+ for (x = 6; x < VFS_IMG_WIDTH + 6; x++)
+ if (vdev->buffer[offset(x, y)] > VFS_IMG_MIN_IMAGE_LEVEL)
+ vdev->buffer[offset(x, y)] = 255;
+};
+
+/* Copy image from reader buffer and put it into image data */
+static void img_copy(struct vfs101_dev *vdev, struct fp_img *img)
+{
+ unsigned int line;
+ unsigned char *img_buffer = img->data;
+ unsigned char *vdev_buffer = vdev->buffer + (vdev->bottom * VFS_FRAME_SIZE) + 6;
+
+ for (line = 0; line < img->height; line++)
+ {
+ /* Copy image line from reader buffer to image data */
+ memcpy(img_buffer, vdev_buffer, VFS_IMG_WIDTH);
+
+ /* Next line of reader buffer */
+ vdev_buffer = vdev_buffer + VFS_FRAME_SIZE;
+
+ /* Next line of image buffer */
+ img_buffer = img_buffer + VFS_IMG_WIDTH;
+ }
+}
+
+/* Extract fingerpint image from raw data */
+static void img_extract(struct fpi_ssm *ssm)
+{
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+ struct fp_img *img;
+ unsigned int height;
+
+ /* Screen image to remove noise and find top and bottom line */
+ img_screen(vdev);
+
+ height = vdev->top - vdev->bottom + 1;
+
+ /* Check image height */
+ if (height < VFS_IMG_MIN_HEIGHT)
+ {
+ fp_warn("image too small, height = %d", height);
+ fpi_imgdev_session_error(dev, result_code(dev, RESULT_RETRY_SHORT));
+ return;
+ }
+
+ /* Fingerprint is present, load image from reader */
+ fpi_imgdev_report_finger_status(dev, TRUE);
+
+ /* Create new image */
+ img = fpi_img_new(height * VFS_IMG_WIDTH);
+ img->width = VFS_IMG_WIDTH;
+ img->height = height;
+ img->flags = FP_IMG_V_FLIPPED;
+
+ /* Copy data into image */
+ img_copy(vdev, img);
+
+ /* Notify image captured */
+ fpi_imgdev_image_captured(dev, img);
+
+ /* Check captured result */
+ if (dev->action_result >= 0 &&
+ dev->action_result != FP_ENROLL_RETRY &&
+ dev->action_result != FP_VERIFY_RETRY)
+ {
+ /* Image captured, increase enroll stage */
+ vdev->enroll_stage++;
+
+ /* Check if action is completed */
+ if (!action_completed(dev))
+ dev->action_result = FP_ENROLL_PASS;
+ }
+ else
+ {
+ /* Image capture failed */
+ if (dev->action == IMG_ACTION_ENROLL)
+ /* Return retry */
+ dev->action_result = result_code(dev, RESULT_RETRY);
+ else
+ {
+ /* Return no match */
+ vdev->enroll_stage++;
+ dev->action_result = FP_VERIFY_NO_MATCH;
+ }
+ }
+
+ /* Fingerprint is removed from reader */
+ fpi_imgdev_report_finger_status(dev, FALSE);
+};
+
+/* Finger states */
+enum
+{
+ VFS_FINGER_EMPTY,
+ VFS_FINGER_PRESENT,
+ VFS_FINGER_UNKNOWN,
+};
+
+/* Return finger state */
+static inline int vfs_finger_state(struct vfs101_dev *vdev)
+{
+ /* Check finger state */
+ switch (vdev->buffer[0x0a])
+ {
+ case 0x00:
+ case 0x01:
+ /* Finger is empty */
+ return VFS_FINGER_EMPTY;
+ break;
+
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ /* Finger is present */
+ return VFS_FINGER_PRESENT;
+ break;
+
+ default:
+ return VFS_FINGER_UNKNOWN;
+ }
+};
+
+/* Loop ssm states */
+enum
+{
+ /* Step 1 - Check state */
+ M_LOOP_1_GET_STATE,
+ M_LOOP_1_CHECK_STATE,
+
+ /* Step 2 - Handle unexpected finger found */
+ M_LOOP_2_SLEEP,
+ M_LOOP_2_GET_PRINT,
+ M_LOOP_2_LOAD_IMAGE,
+ M_LOOP_2_GET_STATE,
+ M_LOOP_2_CHECK_STATE,
+
+ /* Step 3 - Abort print */
+ M_LOOP_3_ABORT_PRINT,
+ M_LOOP_3_LOAD_IMAGE,
+
+ /* Step 4 - Set parameters */
+ M_LOOP_4_SET_INFO_CONTRAST,
+ M_LOOP_4_SET_INFO_RATE,
+
+ /* Step 5 - Scan finger */
+ M_LOOP_5_GET_PRINT,
+ M_LOOP_5_SLEEP,
+ M_LOOP_5_GET_STATE,
+ M_LOOP_5_LOAD_IMAGE,
+
+ /* Step 6 - Extract image */
+ M_LOOP_6_EXRACT_IMAGE,
+ M_LOOP_6_CHECK_ACTION,
+
+ /* Number of states */
+ M_LOOP_NUM_STATES,
+};
+
+/* Exec loop sequential state machine */
+static void m_loop_state(struct fpi_ssm *ssm)
+{
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+
+ /* Check action state */
+ if (!vdev->active)
+ {
+ /* Action not active, mark sequential state machine completed */
+ fpi_ssm_mark_completed(ssm);
+ return;
+ }
+
+ switch (ssm->cur_state)
+ {
+ case M_LOOP_1_GET_STATE:
+ /* Get finger state */
+ vfs_get_finger_state(ssm);
+ break;
+
+ case M_LOOP_1_CHECK_STATE:
+ /* Check finger state */
+ if (vfs_finger_state(vdev) == VFS_FINGER_PRESENT)
+ {
+ /* The user should remove their finger from the scanner */
+ fpi_ssm_next_state(ssm);
+ }
+ else
+ /* Finger not present, continue */
+ fpi_ssm_jump_to_state(ssm, M_LOOP_3_ABORT_PRINT);
+ break;
+
+ case M_LOOP_2_SLEEP:
+ /* Wait fingerprint scanning */
+ async_sleep(500, ssm);
+ break;
+
+ case M_LOOP_2_GET_PRINT:
+ /* Send get print command to the reader */
+ vfs_get_print(ssm, VFS_IMG_MAX_HEIGHT, 1);
+ break;
+
+ case M_LOOP_2_LOAD_IMAGE:
+ /* Load unexpected image */
+ vdev->ignore_error = TRUE;
+ img_load(ssm);
+ break;
+
+ case M_LOOP_2_GET_STATE:
+ /* Get finger state */
+ vfs_get_finger_state(ssm);
+ break;
+
+ case M_LOOP_2_CHECK_STATE:
+ /* Check finger state */
+ if (vfs_finger_state(vdev) == VFS_FINGER_PRESENT)
+ {
+ /* The user should remove their finger from the scanner */
+ fp_warn("Unexpected finger find, remove finger from the scanner");
+ fpi_imgdev_session_error(dev, result_code(dev, RESULT_RETRY_REMOVE));
+ fpi_ssm_jump_to_state(ssm, M_LOOP_2_SLEEP);
+ }
+ else
+ /* Finger not present, continue */
+ fpi_ssm_next_state(ssm);
+ break;
+
+ case M_LOOP_3_ABORT_PRINT:
+ /* Send abort print command */
+ vfs_abort_print(ssm);
+ break;
+
+ case M_LOOP_3_LOAD_IMAGE:
+ /* Load abort image */
+ vdev->ignore_error = TRUE;
+ img_load(ssm);
+ break;
+
+ case M_LOOP_4_SET_INFO_CONTRAST:
+ /* Set info line contrast */
+ vfs_set_param(ssm, VFS_PAR_INFO_CONTRAST, VFS_VAL_INFO_CONTRAST);
+ break;
+
+ case M_LOOP_4_SET_INFO_RATE:
+ /* Set info line rate */
+ vfs_set_param(ssm, VFS_PAR_INFO_RATE, VFS_VAL_INFO_RATE);
+ break;
+
+ case M_LOOP_5_GET_PRINT:
+ /* Send get print command to the reader */
+ vfs_get_print(ssm, VFS_IMG_MAX_HEIGHT, 1);
+ break;
+
+ case M_LOOP_5_SLEEP:
+ /* Wait fingerprint scanning */
+ async_sleep(50, ssm);
+ break;
+
+ case M_LOOP_5_GET_STATE:
+ /* Get finger state */
+ vfs_get_finger_state(ssm);
+ break;
+
+ case M_LOOP_5_LOAD_IMAGE:
+ /* Check finger state */
+ switch (vfs_finger_state(vdev))
+ {
+ case VFS_FINGER_EMPTY:
+ /* Finger isn't present, loop */
+ fpi_ssm_jump_to_state(ssm, M_LOOP_5_SLEEP);
+ break;
+
+ case VFS_FINGER_PRESENT:
+ /* Load image from reader */
+ img_load(ssm);
+ break;
+
+ default:
+ /* Unknown state */
+ fp_err("unknown device state 0x%02x", vdev->buffer[0x0a]);
+ fpi_imgdev_session_error(dev, -EPROTO);
+ fpi_ssm_mark_aborted(ssm, -EPROTO);
+ break;
+ }
+ break;
+
+ case M_LOOP_6_EXRACT_IMAGE:
+ /* Check if image is loaded */
+ if (vdev->length)
+ /* Fingerprint is loaded, extract image from raw data */
+ img_extract(ssm);
+
+ /* Recv eventualy dirty data */
+ vdev->ignore_error = TRUE;
+ async_recv(ssm);
+ break;
+
+ case M_LOOP_6_CHECK_ACTION:
+ /* Check if action is completed */
+ if (!action_completed(dev))
+ fpi_ssm_jump_to_state(ssm, M_LOOP_1_GET_STATE);
+ else
+ fpi_ssm_next_state(ssm);
+ break;
+
+ }
+}
+
+/* Complete loop sequential state machine */
+static void m_loop_complete(struct fpi_ssm *ssm)
+{
+ /* Free sequential state machine */
+ fpi_ssm_free(ssm);
+}
+
+/* Init ssm states */
+enum
+{
+ /* Step 0 - Recv eventualy dirty date */
+ M_INIT_0_RECV_DIRTY,
+
+ /* Step 1 - Abort print */
+ M_INIT_1_ABORT_PRINT,
+ M_INIT_1_LOAD_IMAGE,
+
+ /* Step 2 - Set parameters */
+ M_INIT_2_SET_000E,
+ M_INIT_2_SET_0011,
+ M_INIT_2_SET_0076,
+ M_INIT_2_SET_0078,
+ M_INIT_2_SET_THRESHOLD,
+ M_INIT_2_SET_STATE3_COUNT,
+ M_INIT_2_SET_STATE5_COUNT,
+ M_INIT_2_SET_CONTRAST,
+ M_INIT_2_SET_EXPOSURE,
+
+ /* Step 3 - Get print type 0 */
+ M_INIT_3_GET_PRINT,
+ M_INIT_3_LOAD_IMAGE,
+
+ /* Step 4 - Get print type 1 */
+ M_INIT_4_GET_PRINT,
+ M_INIT_4_LOAD_IMAGE,
+ M_INIT_4_SLEEP,
+
+ /* Number of states */
+ M_INIT_NUM_STATES,
+};
+
+/* Exec init sequential state machine */
+static void m_init_state(struct fpi_ssm *ssm)
+{
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+
+ /* Check action state */
+ if (!vdev->active)
+ {
+ /* Action not active, mark sequential state machine completed */
+ fpi_ssm_mark_completed(ssm);
+ return;
+ }
+
+ switch (ssm->cur_state)
+ {
+ case M_INIT_0_RECV_DIRTY:
+ /* Recv eventualy dirty data */
+ vdev->ignore_error = TRUE;
+ async_recv(ssm);
+ break;
+
+ case M_INIT_1_ABORT_PRINT:
+ /* Send abort print command */
+ vfs_abort_print(ssm);
+ break;
+
+ case M_INIT_1_LOAD_IMAGE:
+ /* Load abort image */
+ vdev->ignore_error = TRUE;
+ img_load(ssm);
+ break;
+
+ case M_INIT_2_SET_000E:
+ /* Set param 0x000e, required for take image */
+ vfs_set_param(ssm, VFS_PAR_000E, VFS_VAL_000E);
+ break;
+
+ case M_INIT_2_SET_0011:
+ /* Set param 0x0011, required for take image */
+ vfs_set_param(ssm, VFS_PAR_0011, VFS_VAL_0011);
+ break;
+
+ case M_INIT_2_SET_0076:
+ /* Set param 0x0076, required for use info line */
+ vfs_set_param(ssm, VFS_PAR_0076, VFS_VAL_0076);
+ break;
+
+ case M_INIT_2_SET_0078:
+ /* Set param 0x0078, required for use info line */
+ vfs_set_param(ssm, VFS_PAR_0078, VFS_VAL_0078);
+ break;
+
+ case M_INIT_2_SET_THRESHOLD:
+ /* Set threshold */
+ vfs_set_param(ssm, VFS_PAR_THRESHOLD, VFS_VAL_THRESHOLD);
+ break;
+
+ case M_INIT_2_SET_STATE3_COUNT:
+ /* Set state 3 count */
+ vfs_set_param(ssm, VFS_PAR_STATE_3, VFS_VAL_STATE_3);
+ break;
+
+ case M_INIT_2_SET_STATE5_COUNT:
+ /* Set state 5 count */
+ vfs_set_param(ssm, VFS_PAR_STATE_5, VFS_VAL_STATE_5);
+ break;
+
+ case M_INIT_2_SET_CONTRAST:
+ /* Set contrast level of reader */
+ vfs_poke(ssm, VFS_REG_IMG_CONTRAST, VFS_VAL_IMG_CONTRAST, 0x01);
+ break;
+
+ case M_INIT_2_SET_EXPOSURE:
+ /* Set exposure level of reader */
+ vfs_poke(ssm, VFS_REG_IMG_EXPOSURE, VFS_VAL_IMG_EXPOSURE, 0x02);
+ break;
+
+ case M_INIT_3_GET_PRINT:
+ /* Get empty image */
+ vfs_get_print(ssm, 0x0014, 0);
+ break;
+
+ case M_INIT_3_LOAD_IMAGE:
+ /* Load empty image */
+ img_load(ssm);
+ break;
+
+ case M_INIT_4_GET_PRINT:
+ /* Send get print command to the reader */
+ vfs_get_print(ssm, VFS_IMG_MAX_HEIGHT, 1);
+ break;
+
+ case M_INIT_4_LOAD_IMAGE:
+ /* Load unexpected image */
+ vdev->ignore_error = TRUE;
+ img_load(ssm);
+ break;
+
+ case M_INIT_4_SLEEP:
+ /* Wait fingerprint scanning */
+ async_sleep(50, ssm);
+ break;
+ }
+}
+
+/* Complete init sequential state machine */
+static void m_init_complete(struct fpi_ssm *ssm)
+{
+ struct fp_img_dev *dev = ssm->priv;
+ struct vfs101_dev *vdev = dev->priv;
+ struct fpi_ssm *ssm_loop;
+
+ if (!ssm->error && vdev->active)
+ {
+ /* Start loop ssm */
+ ssm_loop = fpi_ssm_new(dev->dev, m_loop_state, M_LOOP_NUM_STATES);
+ ssm_loop->priv = dev;
+ fpi_ssm_start(ssm_loop, m_loop_complete);
+ }
+
+ /* Free sequential state machine */
+ fpi_ssm_free(ssm);
+}
+
+/* Activate device */
+static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
+{
+ struct vfs101_dev *vdev = dev->priv;
+ struct fpi_ssm *ssm;
+
+ /* Check if already active */
+ if (vdev->active)
+ {
+ fp_err("device already activated");
+ fpi_imgdev_session_error(dev, -EBUSY);
+ return 1;
+ }
+
+ /* Set active state */
+ vdev->active = TRUE;
+
+ /* Reset enroll stage */
+ vdev->enroll_stage = 0;
+
+ /* Start init ssm */
+ ssm = fpi_ssm_new(dev->dev, m_init_state, M_INIT_NUM_STATES);
+ ssm->priv = dev;
+ fpi_ssm_start(ssm, m_init_complete);
+
+ /* Notify activate complete */
+ fpi_imgdev_activate_complete(dev, 0);
+
+ return 0;
+}
+
+/* Deactivate device */
+static void dev_deactivate(struct fp_img_dev *dev)
+{
+ struct vfs101_dev *vdev = dev->priv;
+
+ /* Reset active state */
+ vdev->active = FALSE;
+
+ /* Handle eventualy existing events */
+ while (vdev->transfer || vdev->timeout)
+ fp_handle_events();
+
+ /* Notify deactivate complete */
+ fpi_imgdev_deactivate_complete(dev);
+}
+
+/* Open device */
+static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
+{
+ struct vfs101_dev *vdev = NULL;
+ int r;
+
+ /* Claim usb interface */
+ r = libusb_claim_interface(dev->udev, 0);
+ if (r < 0)
+ {
+ /* Interface not claimed, return error */
+ fp_err("could not claim interface 0");
+ return r;
+ }
+
+ /* Set enroll stage number */
+ dev->dev->nr_enroll_stages = VFS_NR_ENROLL;
+
+ /* Initialize private structure */
+ vdev = g_malloc0(sizeof(struct vfs101_dev));
+ vdev->seqnum = -1;
+ dev->priv = vdev;
+
+ /* Notify open complete */
+ fpi_imgdev_open_complete(dev, 0);
+
+ return 0;
+}
+
+/* Close device */
+static void dev_close(struct fp_img_dev *dev)
+{
+ /* Release private structure */
+ g_free(dev->priv);
+
+ /* Release usb interface */
+ libusb_release_interface(dev->udev, 0);
+
+ /* Notify close complete */
+ fpi_imgdev_close_complete(dev);
+}
+
+/* Usb id table of device */
+static const struct usb_id id_table[] =
+{
+ { .vendor = 0x138a, .product = 0x0001 },
+ { 0, 0, 0, },
+};
+
+/* Device driver definition */
+struct fp_img_driver vfs101_driver =
+{
+ /* Driver specification */
+ .driver =
+ {
+ .id = 10,
+ .name = FP_COMPONENT,
+ .full_name = "Validity VFS101",
+ .id_table = id_table,
+ .scan_type = FP_SCAN_TYPE_SWIPE,
+ },
+
+ /* Image specification */
+ .flags = 0,
+ .img_width = VFS_IMG_WIDTH,
+ .img_height = -1,
+ .bz3_threshold = 20,
+
+ /* Routine specification */
+ .open = dev_open,
+ .close = dev_close,
+ .activate = dev_activate,
+ .deactivate = dev_deactivate,
+};
--- ./libfprint/fp_internal.h.orig 2010-11-03 12:39:34.325159723 +0100
+++ ./libfprint/fp_internal.h 2011-02-10 15:34:02.258394925 +0100
@@ -265,6 +265,9 @@
#ifdef ENABLE_VCOM5S
extern struct fp_img_driver vcom5s_driver;
#endif
+#ifdef ENABLE_VFS101
+extern struct fp_img_driver vfs101_driver;
+#endif
extern libusb_context *fpi_usb_ctx;
extern GSList *opened_devices;
--- ./libfprint/core.c.orig 2010-11-03 12:38:08.624383608 +0100
+++ ./libfprint/core.c 2010-11-09 12:39:21.633836762 +0100
@@ -368,6 +368,9 @@
#ifdef ENABLE_AES1610
&aes1610_driver,
#endif
+#ifdef ENABLE_VFS101
+ &vfs101_driver,
+#endif
/*#ifdef ENABLE_UPEKTC
&upektc_driver,
#endif
--- ./libfprint/poll.c.orig 2011-02-11 22:32:55.186998770 +0100
+++ ./libfprint/poll.c 2011-02-16 15:17:59.945823445 +0100
@@ -270,6 +270,14 @@
if (r_fprint == 0 && r_libusb == 0)
return 0;
+ /* if fprint have no pending timeouts return libusb timeout */
+ else if (r_fprint == 0)
+ *tv = libusb_timeout;
+
+ /* if libusb have no pending timeouts return fprint timeout */
+ else if (r_libusb == 0)
+ *tv = fprint_timeout;
+
/* otherwise return the smaller of the 2 timeouts */
else if (timercmp(&fprint_timeout, &libusb_timeout, <))
*tv = fprint_timeout;
--- ./libfprint/gdkpixbuf.c.orig 2011-02-22 13:51:05.136410197 +0100
+++ ./libfprint/gdkpixbuf.c 2011-02-23 09:11:03.669226493 +0100
@@ -75,7 +75,7 @@
for (x = 0; x < newimg->width; x++) {
guchar *p, *r;
- r = img->data + y * img->width + x;
+ r = newimg->data + y * newimg->width + x;
p = pixels + y * rowstride + x * 3;
r[0] = p[0];
}
--- ./libfprint/Makefile.am.orig 2010-11-03 12:27:45.385133988 +0100
+++ ./libfprint/Makefile.am 2010-11-09 12:38:41.184676308 +0100
@@ -12,6 +12,7 @@
AES4000_SRC = drivers/aes4000.c
FDU2000_SRC = drivers/fdu2000.c
VCOM5S_SRC = drivers/vcom5s.c
+VFS101_SRC = drivers/vfs101.c
EXTRA_DIST = \
$(UPEKE2_SRC) \
@@ -24,6 +25,7 @@
$(AES4000_SRC) \
$(FDU2000_SRC) \
$(VCOM5S_SRC) \
+ $(VFS101_SRC) \
aeslib.c aeslib.h \
imagemagick.c \
gdkpixbuf.c
@@ -122,6 +124,10 @@
DRIVER_SRC += $(AES4000_SRC)
endif
+if ENABLE_VFS101
+DRIVER_SRC += $(VFS101_SRC)
+endif
+
if REQUIRE_IMAGEMAGICK
OTHER_SRC += imagemagick.c
libfprint_la_CFLAGS += $(IMAGING_CFLAGS)
--- ./configure.ac.orig 2010-11-03 09:55:01.698383993 +0100
+++ ./configure.ac 2010-11-09 12:36:56.961588962 +0100
@@ -20,7 +20,7 @@
AC_SUBST(lt_revision)
AC_SUBST(lt_age)
-all_drivers="upeke2 upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes2501 aes4000"
+all_drivers="upeke2 upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes2501 aes4000 vfs101"
require_imaging='no'
require_aeslib='no'
@@ -34,6 +34,7 @@
enable_aes1610='no'
enable_aes2501='no'
enable_aes4000='no'
+enable_vfs101='no'
AC_ARG_WITH([drivers],[AS_HELP_STRING([--with-drivers],
[List of drivers to enable])],
@@ -88,6 +89,10 @@
require_imaging="yes"
enable_aes4000="yes"
;;
+ vfs101)
+ AC_DEFINE([ENABLE_VFS101], [], [Build Validity VFS101 driver])
+ enable_vfs101="yes"
+ ;;
esac
done
@@ -102,6 +107,7 @@
AM_CONDITIONAL([ENABLE_AES2501], [test "$enable_aes2501" = "yes"])
AM_CONDITIONAL([ENABLE_AES4000], [test "$enable_aes4000" = "yes"])
AM_CONDITIONAL([REQUIRE_AESLIB], [test "$require_aeslib" = "yes"])
+AM_CONDITIONAL([ENABLE_VFS101], [test "$enable_vfs101" = "yes"])
PKG_CHECK_MODULES(LIBUSB, [libusb-1.0 >= 0.9.1])
@@ -263,6 +269,11 @@
else
AC_MSG_NOTICE([ aes4000 driver disabled])
fi
+if test x$enable_vfs101 != xno ; then
+ AC_MSG_NOTICE([** vfs101 driver enabled])
+else
+ AC_MSG_NOTICE([ vfs101 driver disabled])
+fi
if test x$require_aeslib != xno ; then
AC_MSG_NOTICE([** aeslib helper functions enabled])
else
_______________________________________________
fprint mailing list
[email protected]
http://lists.reactivated.net/mailman/listinfo/fprint