1255 lines
33 KiB
Diff
1255 lines
33 KiB
Diff
diff --git a/configure.ac b/configure.ac
|
||
index 052ef0e..a892a96 100644
|
||
--- a/configure.ac
|
||
+++ b/configure.ac
|
||
@@ -89,7 +89,7 @@ AM_CONDITIONAL([ENABLE_UPEKSONLY], [test "$enable_upeksonly" != "no"])
|
||
AM_CONDITIONAL([ENABLE_VCOM5S], [test "$enable_vcom5s" != "no"])
|
||
AM_CONDITIONAL([ENABLE_URU4000], [test "$enable_uru4000" != "no"])
|
||
#AM_CONDITIONAL([ENABLE_FDU2000], [test "$enable_fdu2000" != "no"])
|
||
-#AM_CONDITIONAL([ENABLE_AES1610], [test "$enable_aes1610" != "no"])
|
||
+AM_CONDITIONAL([ENABLE_AES1610], [test "$enable_aes1610" != "no"])
|
||
AM_CONDITIONAL([ENABLE_AES2501], [test "$enable_aes2501" != "no"])
|
||
AM_CONDITIONAL([ENABLE_AES4000], [test "$enable_aes4000" != "no"])
|
||
AM_CONDITIONAL([REQUIRE_AESLIB], [test "$require_aeslib" != "no"])
|
||
diff --git a/libfprint/Makefile.am b/libfprint/Makefile.am
|
||
index c79012b..8316796 100644
|
||
--- a/libfprint/Makefile.am
|
||
+++ b/libfprint/Makefile.am
|
||
@@ -100,9 +100,9 @@ endif
|
||
#DRIVER_SRC += $(FDU2000_SRC)
|
||
#endif
|
||
|
||
-#if ENABLE_AES1610
|
||
-#DRIVER_SRC += $(AES1610_SRC)
|
||
-#endif
|
||
+if ENABLE_AES1610
|
||
+DRIVER_SRC += $(AES1610_SRC)
|
||
+endif
|
||
|
||
if ENABLE_AES2501
|
||
DRIVER_SRC += $(AES2501_SRC)
|
||
diff --git a/libfprint/core.c b/libfprint/core.c
|
||
index 37a4e03..724d5e5 100644
|
||
--- a/libfprint/core.c
|
||
+++ b/libfprint/core.c
|
||
@@ -361,11 +361,11 @@ static struct fp_img_driver * const img_drivers[] = {
|
||
#ifdef ENABLE_UPEKSONLY
|
||
&upeksonly_driver,
|
||
#endif
|
||
- /*
|
||
+
|
||
#ifdef ENABLE_AES1610
|
||
&aes1610_driver,
|
||
#endif
|
||
-#ifdef ENABLE_UPEKTC
|
||
+/*#ifdef ENABLE_UPEKTC
|
||
&upektc_driver,
|
||
#endif
|
||
#ifdef ENABLE_FDU2000
|
||
diff --git a/libfprint/drivers/aes1610.c b/libfprint/drivers/aes1610.c
|
||
index 318195f..8b81a80 100644
|
||
--- a/libfprint/drivers/aes1610.c
|
||
+++ b/libfprint/drivers/aes1610.c
|
||
@@ -1,11 +1,11 @@
|
||
/*
|
||
* AuthenTec AES1610 driver for libfprint
|
||
- * Copyright (C) 2007 Anthony Bretaudeau <wxcover@users.sourceforge.net>
|
||
- * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
||
+ * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||
* Copyright (C) 2007 Cyrille Bagard
|
||
* Copyright (C) 2007 Vasily Khoruzhick
|
||
+ * Copyright (C) 2009 Guido Grazioli <guido.grazioli@gmail.com>
|
||
*
|
||
- * Based on code from http://home.gna.org/aes2501, relicensed with permission
|
||
+ * Based on code from libfprint aes2501 driver.
|
||
*
|
||
* This library is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU Lesser General Public
|
||
@@ -32,15 +32,22 @@
|
||
#include <aeslib.h>
|
||
#include <fp_internal.h>
|
||
|
||
+static void start_capture(struct fp_img_dev *dev);
|
||
+static void complete_deactivation(struct fp_img_dev *dev);
|
||
+static int adjust_gain(unsigned char *buffer, int status);
|
||
+
|
||
+#define FIRST_AES1610_REG 0x1B
|
||
+#define LAST_AES1610_REG 0xFF
|
||
+
|
||
+#define GAIN_STATUS_FIRST 1
|
||
+#define GAIN_STATUS_NORMAL 2
|
||
+
|
||
/* FIXME these need checking */
|
||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||
|
||
#define BULK_TIMEOUT 4000
|
||
|
||
-#define FIRST_AES1610_REG 0x1B
|
||
-#define LAST_AES1610_REG 0xFF
|
||
-
|
||
/*
|
||
* The AES1610 is an imaging device using a swipe-type sensor. It samples
|
||
* the finger at preprogrammed intervals, sending a 128x8 frame to the
|
||
@@ -53,140 +60,212 @@
|
||
* images returned from this driver vary in height.
|
||
*/
|
||
|
||
-#define FRAME_WIDTH 128
|
||
+#define FRAME_WIDTH 128
|
||
#define FRAME_HEIGHT 8
|
||
-#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
||
+#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
||
/* maximum number of frames to read during a scan */
|
||
/* FIXME reduce substantially */
|
||
#define MAX_FRAMES 350
|
||
|
||
-static int read_data(struct fp_img_dev *dev, unsigned char *data, size_t len)
|
||
+/****** GENERAL FUNCTIONS ******/
|
||
+
|
||
+struct aes1610_dev {
|
||
+ uint8_t read_regs_retry_count;
|
||
+ GSList *strips;
|
||
+ size_t strips_len;
|
||
+ gboolean deactivating;
|
||
+ uint8_t blanks_count;
|
||
+};
|
||
+
|
||
+typedef void (*aes1610_read_regs_cb)(struct fp_img_dev *dev, int status,
|
||
+ unsigned char *regs, void *user_data);
|
||
+
|
||
+struct aes1610_read_regs {
|
||
+ struct fp_img_dev *dev;
|
||
+ aes1610_read_regs_cb callback;
|
||
+ struct aes_regwrite *regwrite;
|
||
+ void *user_data;
|
||
+};
|
||
+
|
||
+/* FIXME: what to do here? */
|
||
+static void stub_capture_stop_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||
{
|
||
- int r;
|
||
- int transferred;
|
||
- struct libusb_bulk_transfer msg = {
|
||
- .endpoint = EP_IN,
|
||
- .data = data,
|
||
- .length = len,
|
||
- };
|
||
- fp_dbg("len=%zd", len);
|
||
|
||
- r = libusb_bulk_transfer(dev->udev, &msg, &transferred, BULK_TIMEOUT);
|
||
- if (r < 0) {
|
||
- fp_err("bulk read error %d", r);
|
||
- return r;
|
||
- } else if (transferred < len) {
|
||
- fp_err("unexpected short read %d/%zd", r, len);
|
||
- return -EIO;
|
||
- }
|
||
- return 0;
|
||
}
|
||
|
||
-static const struct aes_regwrite init[] = {
|
||
- { 0x82, 0x00 }
|
||
-};
|
||
|
||
-static const struct aes_regwrite stop_reader[] = {
|
||
- { 0xFF, 0x00 }
|
||
-};
|
||
+/* check that read succeeded but ignore all data */
|
||
+static void generic_ignore_data_cb(struct libusb_transfer *transfer)
|
||
+{
|
||
+ struct fpi_ssm *ssm = transfer->user_data;
|
||
|
||
-static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||
+ fpi_ssm_mark_aborted(ssm, -EIO);
|
||
+ else if (transfer->length != transfer->actual_length)
|
||
+ fpi_ssm_mark_aborted(ssm, -EPROTO);
|
||
+ else
|
||
+ fpi_ssm_next_state(ssm);
|
||
+
|
||
+ g_free(transfer->buffer);
|
||
+ libusb_free_transfer(transfer);
|
||
+}
|
||
+
|
||
+
|
||
+static void read_regs_data_cb(struct libusb_transfer *transfer)
|
||
{
|
||
+ struct aes1610_read_regs *rdata = transfer->user_data;
|
||
+ unsigned char *retdata = NULL;
|
||
int r;
|
||
|
||
- r = libusb_claim_interface(dev->udev, 0);
|
||
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||
+ r = -EIO;
|
||
+ } else if (transfer->length != transfer->actual_length) {
|
||
+ r = -EPROTO;
|
||
+ } else {
|
||
+ r = 0;
|
||
+ retdata = transfer->buffer;
|
||
+ }
|
||
+
|
||
+ rdata->callback(rdata->dev, r, retdata, rdata->user_data);
|
||
+ g_free(rdata);
|
||
+ g_free(transfer->buffer);
|
||
+ libusb_free_transfer(transfer);
|
||
+}
|
||
+
|
||
+static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||
+{
|
||
+ struct aes1610_read_regs *rdata = user_data;
|
||
+ struct libusb_transfer *transfer;
|
||
+ unsigned char *data;
|
||
+ int r;
|
||
+
|
||
+ g_free(rdata->regwrite);
|
||
+ if (result != 0)
|
||
+ goto err;
|
||
+
|
||
+ transfer = libusb_alloc_transfer(0);
|
||
+ if (!transfer) {
|
||
+ result = -ENOMEM;
|
||
+ goto err;
|
||
+ }
|
||
+
|
||
+ data = g_malloc(126);
|
||
+ libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 126,
|
||
+ read_regs_data_cb, rdata, BULK_TIMEOUT);
|
||
+
|
||
+ r = libusb_submit_transfer(transfer);
|
||
if (r < 0) {
|
||
- fp_err("could not claim interface 0");
|
||
- return r;
|
||
+ g_free(data);
|
||
+ libusb_free_transfer(transfer);
|
||
+ result = -EIO;
|
||
+ goto err;
|
||
}
|
||
|
||
- /* FIXME check endpoints */
|
||
+ return;
|
||
+err:
|
||
+ rdata->callback(dev, result, NULL, rdata->user_data);
|
||
+ g_free(rdata);
|
||
+}
|
||
|
||
- return aes_write_regv(dev, init, G_N_ELEMENTS(init));
|
||
+
|
||
+// XXX: this comes from aes2501 driver but it is unused here
|
||
+static void read_regs(struct fp_img_dev *dev, aes1610_read_regs_cb callback,
|
||
+ void *user_data)
|
||
+{
|
||
+ /* FIXME: regwrite is dynamic because of asynchronity. is this really
|
||
+ * required? */
|
||
+ struct aes_regwrite *regwrite = g_malloc(sizeof(*regwrite));
|
||
+ struct aes1610_read_regs *rdata = g_malloc(sizeof(*rdata));
|
||
+
|
||
+ fp_dbg("");
|
||
+ //regwrite->reg = AES1610_REG_CTRL2;
|
||
+ //regwrite->value = AES1610_CTRL2_READ_REGS;
|
||
+ rdata->dev = dev;
|
||
+ rdata->callback = callback;
|
||
+ rdata->user_data = user_data;
|
||
+ rdata->regwrite = regwrite;
|
||
+
|
||
+ //aes_write_regv(dev, (const struct aes_regwrite *) regwrite, 1,
|
||
+ // read_regs_rq_cb, rdata);
|
||
}
|
||
|
||
-static int do_exit(struct fp_img_dev *dev)
|
||
+/* Read the value of a specific register from a register dump */
|
||
+static int regval_from_dump(unsigned char *data, uint8_t target)
|
||
{
|
||
- return aes_write_regv(dev, stop_reader, G_N_ELEMENTS(stop_reader));
|
||
+ if (*data != FIRST_AES1610_REG) {
|
||
+ fp_err("not a register dump");
|
||
+ return -EILSEQ;
|
||
+ }
|
||
+
|
||
+ if (!(FIRST_AES1610_REG <= target && target <= LAST_AES1610_REG)) {
|
||
+ fp_err("out of range");
|
||
+ return -EINVAL;
|
||
+ }
|
||
+
|
||
+ target -= FIRST_AES1610_REG;
|
||
+ target *= 2;
|
||
+ return data[target + 1];
|
||
}
|
||
|
||
-static void dev_exit(struct fp_img_dev *dev)
|
||
+static void generic_write_regv_cb(struct fp_img_dev *dev, int result,
|
||
+ void *user_data)
|
||
{
|
||
- do_exit(dev);
|
||
- libusb_release_interface(dev->udev, 0);
|
||
+ struct fpi_ssm *ssm = user_data;
|
||
+ if (result == 0)
|
||
+ fpi_ssm_next_state(ssm);
|
||
+ else
|
||
+ fpi_ssm_mark_aborted(ssm, result);
|
||
}
|
||
|
||
-static const struct aes_regwrite finger_det_reqs[] = {
|
||
- { 0x80, 0x01 },
|
||
- { 0x80, 0x12 },
|
||
- { 0x85, 0x00 },
|
||
- { 0x8A, 0x00 },
|
||
- { 0x8B, 0x0E },
|
||
- { 0x8C, 0x90 },
|
||
- { 0x8D, 0x83 },
|
||
- { 0x8E, 0x07 },
|
||
- { 0x8F, 0x07 },
|
||
- { 0x96, 0x00 },
|
||
- { 0x97, 0x48 },
|
||
- { 0xA1, 0x00 },
|
||
- { 0xA2, 0x50 },
|
||
- { 0xA6, 0xE4 },
|
||
- { 0xAD, 0x08 },
|
||
- { 0xAE, 0x5B },
|
||
- { 0xAF, 0x54 },
|
||
- { 0xB1, 0x28 },
|
||
- { 0xB5, 0xAB },
|
||
- { 0xB6, 0x0E },
|
||
- { 0x1B, 0x2D },
|
||
- { 0x81, 0x04 }
|
||
-};
|
||
|
||
-static const struct aes_regwrite finger_det_none[] = {
|
||
- { 0x80, 0x01 },
|
||
- { 0x82, 0x00 },
|
||
- { 0x86, 0x00 },
|
||
- { 0xB1, 0x28 },
|
||
- { 0x1D, 0x00 }
|
||
-};
|
||
|
||
-static int detect_finger(struct fp_img_dev *dev)
|
||
+/* read the specified number of bytes from the IN endpoint but throw them
|
||
+ * away, then increment the SSM */
|
||
+static void generic_read_ignore_data(struct fpi_ssm *ssm, size_t bytes)
|
||
{
|
||
- unsigned char buffer[19];
|
||
+ struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||
+ unsigned char *data;
|
||
int r;
|
||
- int i;
|
||
- int sum = 0;
|
||
|
||
- r = aes_write_regv(dev, finger_det_reqs, G_N_ELEMENTS(finger_det_reqs));
|
||
- if (r < 0)
|
||
- return r;
|
||
+ if (!transfer) {
|
||
+ fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
||
+ return;
|
||
+ }
|
||
|
||
- r = read_data(dev, buffer, 19);
|
||
- if (r < 0)
|
||
- return r;
|
||
+ data = g_malloc(bytes);
|
||
+ libusb_fill_bulk_transfer(transfer, ssm->dev->udev, EP_IN, data, bytes,
|
||
+ generic_ignore_data_cb, ssm, BULK_TIMEOUT);
|
||
|
||
- for (i = 3; i < 17; i++)
|
||
- sum += (buffer[i] & 0xf) + (buffer[i] >> 4);
|
||
-
|
||
- /* We need to answer something if no finger has been detected */
|
||
- if (sum <= 20) {
|
||
- r = aes_write_regv(dev, finger_det_none, G_N_ELEMENTS(finger_det_none));
|
||
- if (r < 0)
|
||
- return r;
|
||
+ r = libusb_submit_transfer(transfer);
|
||
+ if (r < 0) {
|
||
+ g_free(data);
|
||
+ libusb_free_transfer(transfer);
|
||
+ fpi_ssm_mark_aborted(ssm, r);
|
||
}
|
||
-
|
||
- return sum > 20;
|
||
}
|
||
|
||
-static int await_finger_on(struct fp_img_dev *dev)
|
||
+/****** IMAGE PROCESSING ******/
|
||
+
|
||
+static int sum_histogram_values(unsigned char *data, uint8_t threshold)
|
||
{
|
||
- int r;
|
||
- do {
|
||
- r = detect_finger(dev);
|
||
- } while (r == 0);
|
||
- return (r < 0) ? r : 0;
|
||
+ int r = 0;
|
||
+ int i;
|
||
+ uint16_t *histogram = (uint16_t *)(data + 1);
|
||
+
|
||
+ if (*data != 0xde)
|
||
+ return -EILSEQ;
|
||
+
|
||
+ if (threshold > 0x0f)
|
||
+ return -EINVAL;
|
||
+
|
||
+ /* FIXME endianness */
|
||
+ for (i = threshold; i < 16; i++)
|
||
+ r += histogram[i];
|
||
+
|
||
+ return r;
|
||
}
|
||
|
||
-/* find overlapping parts of frames */
|
||
+/* find overlapping parts of frames */
|
||
static unsigned int find_overlap(unsigned char *first_frame,
|
||
unsigned char *second_frame, unsigned int *min_error)
|
||
{
|
||
@@ -199,11 +278,11 @@ static unsigned int find_overlap(unsigned char *first_frame,
|
||
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]);
|
||
+ 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;
|
||
@@ -213,37 +292,39 @@ static unsigned int find_overlap(unsigned char *first_frame,
|
||
}
|
||
first_frame += FRAME_WIDTH;
|
||
}
|
||
-
|
||
- return not_overlapped_height;
|
||
+
|
||
+ return not_overlapped_height;
|
||
}
|
||
|
||
/* assemble a series of frames into a single image */
|
||
-static unsigned int assemble(unsigned char *input, unsigned char *output,
|
||
- int num_strips, gboolean reverse, unsigned int *errors_sum)
|
||
+static unsigned int assemble(struct aes1610_dev *aesdev, unsigned char *output,
|
||
+ gboolean reverse, unsigned int *errors_sum)
|
||
{
|
||
uint8_t *assembled = output;
|
||
int frame;
|
||
uint32_t image_height = FRAME_HEIGHT;
|
||
unsigned int min_error;
|
||
+ size_t num_strips = aesdev->strips_len;
|
||
+ GSList *list_entry = aesdev->strips;
|
||
*errors_sum = 0;
|
||
|
||
if (num_strips < 1)
|
||
return 0;
|
||
-
|
||
- /* Rotating given data by 90 degrees
|
||
+
|
||
+ /* Rotating given data by 90 degrees
|
||
* Taken from document describing aes1610 image format
|
||
* TODO: move reversing detection here */
|
||
-
|
||
+
|
||
if (reverse)
|
||
output += (num_strips - 1) * FRAME_SIZE;
|
||
for (frame = 0; frame < num_strips; frame++) {
|
||
- aes_assemble_image(input, FRAME_WIDTH, FRAME_HEIGHT, output);
|
||
- input += FRAME_WIDTH * (FRAME_HEIGHT / 2);
|
||
+ aes_assemble_image(list_entry->data, FRAME_WIDTH, FRAME_HEIGHT, output);
|
||
|
||
if (reverse)
|
||
- output -= FRAME_SIZE;
|
||
+ output -= FRAME_SIZE;
|
||
else
|
||
- output += FRAME_SIZE;
|
||
+ output += FRAME_SIZE;
|
||
+ list_entry = g_slist_next(list_entry);
|
||
}
|
||
|
||
/* Detecting where frames overlaped */
|
||
@@ -256,12 +337,183 @@ static unsigned int assemble(unsigned char *input, unsigned char *output,
|
||
*errors_sum += min_error;
|
||
image_height += not_overlapped;
|
||
assembled += FRAME_WIDTH * not_overlapped;
|
||
- memcpy(assembled, output, FRAME_SIZE);
|
||
+ memcpy(assembled, output, FRAME_SIZE);
|
||
}
|
||
return image_height;
|
||
}
|
||
|
||
-static const struct aes_regwrite capture_reqs[] = {
|
||
+static void assemble_and_submit_image(struct fp_img_dev *dev)
|
||
+{
|
||
+ struct aes1610_dev *aesdev = dev->priv;
|
||
+ size_t final_size;
|
||
+ struct fp_img *img;
|
||
+ unsigned int errors_sum, r_errors_sum;
|
||
+
|
||
+ fp_dbg("");
|
||
+
|
||
+ BUG_ON(aesdev->strips_len == 0);
|
||
+
|
||
+ /* reverse list */
|
||
+ aesdev->strips = g_slist_reverse(aesdev->strips);
|
||
+
|
||
+ /* create buffer big enough for max image */
|
||
+ img = fpi_img_new(aesdev->strips_len * FRAME_SIZE);
|
||
+
|
||
+ img->flags = FP_IMG_COLORS_INVERTED;
|
||
+ img->height = assemble(aesdev, img->data, FALSE, &errors_sum);
|
||
+ img->height = assemble(aesdev, img->data, TRUE, &r_errors_sum);
|
||
+
|
||
+ if (r_errors_sum > errors_sum) {
|
||
+ img->height = assemble(aesdev, img->data, FALSE, &errors_sum);
|
||
+ img->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
|
||
+ fp_dbg("normal scan direction");
|
||
+ } else {
|
||
+ fp_dbg("reversed scan direction");
|
||
+ }
|
||
+
|
||
+ /* now that overlap has been removed, resize output image buffer */
|
||
+ final_size = img->height * FRAME_WIDTH;
|
||
+ img = fpi_img_resize(img, final_size);
|
||
+ /* FIXME: ugly workaround */
|
||
+ if (img->height < 12)
|
||
+ img->height = 12;
|
||
+ fpi_imgdev_image_captured(dev, img);
|
||
+
|
||
+ /* free strips and strip list */
|
||
+ g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL);
|
||
+ g_slist_free(aesdev->strips);
|
||
+ aesdev->strips = NULL;
|
||
+ aesdev->strips_len = 0;
|
||
+ aesdev->blanks_count = 0;
|
||
+}
|
||
+
|
||
+
|
||
+/****** FINGER PRESENCE DETECTION ******/
|
||
+
|
||
+
|
||
+static const struct aes_regwrite finger_det_reqs[] = {
|
||
+ { 0x80, 0x01 },
|
||
+ { 0x80, 0x12 },
|
||
+ { 0x85, 0x00 },
|
||
+ { 0x8A, 0x00 },
|
||
+ { 0x8B, 0x0E },
|
||
+ { 0x8C, 0x90 },
|
||
+ { 0x8D, 0x83 },
|
||
+ { 0x8E, 0x07 },
|
||
+ { 0x8F, 0x07 },
|
||
+ { 0x96, 0x00 },
|
||
+ { 0x97, 0x48 },
|
||
+ { 0xA1, 0x00 },
|
||
+ { 0xA2, 0x50 },
|
||
+ { 0xA6, 0xE4 },
|
||
+ { 0xAD, 0x08 },
|
||
+ { 0xAE, 0x5B },
|
||
+ { 0xAF, 0x54 },
|
||
+ { 0xB1, 0x28 },
|
||
+ { 0xB5, 0xAB },
|
||
+ { 0xB6, 0x0E },
|
||
+ { 0x1B, 0x2D },
|
||
+ { 0x81, 0x04 }
|
||
+};
|
||
+
|
||
+static const struct aes_regwrite finger_det_none[] = {
|
||
+ { 0x80, 0x01 },
|
||
+ { 0x82, 0x00 },
|
||
+ { 0x86, 0x00 },
|
||
+ { 0xB1, 0x28 },
|
||
+ { 0x1D, 0x00 }
|
||
+};
|
||
+
|
||
+
|
||
+static void start_finger_detection(struct fp_img_dev *dev);
|
||
+
|
||
+static void finger_det_data_cb(struct libusb_transfer *transfer)
|
||
+{
|
||
+ struct fp_img_dev *dev = transfer->user_data;
|
||
+ unsigned char *data = transfer->buffer;
|
||
+ int i;
|
||
+ int sum = 0;
|
||
+
|
||
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||
+ fpi_imgdev_session_error(dev, -EIO);
|
||
+ goto out;
|
||
+ } else if (transfer->length != transfer->actual_length) {
|
||
+ fpi_imgdev_session_error(dev, -EPROTO);
|
||
+ goto out;
|
||
+ }
|
||
+
|
||
+ /* examine histogram to determine finger presence */
|
||
+ for (i = 3; i < 17; i++)
|
||
+ sum += (data[i] & 0xf) + (data[i] >> 4);
|
||
+ if (sum > 20) {
|
||
+ /* reset default gain */
|
||
+ adjust_gain(data,GAIN_STATUS_FIRST);
|
||
+ /* finger present, start capturing */
|
||
+ fpi_imgdev_report_finger_status(dev, TRUE);
|
||
+ start_capture(dev);
|
||
+ } else {
|
||
+ /* no finger, poll for a new histogram */
|
||
+ start_finger_detection(dev);
|
||
+ }
|
||
+
|
||
+out:
|
||
+ g_free(data);
|
||
+ libusb_free_transfer(transfer);
|
||
+}
|
||
+
|
||
+
|
||
+static void finger_det_none_cb(struct fp_img_dev *dev, int result, void *user_data) |