From be67f85caa1c65c4c55d4e969d757e7f2790bd7e Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sat, 27 Oct 2007 18:12:16 +0100 Subject: [PATCH] Add Authentec AES4000 driver --- TODO | 1 - libfprint/Makefile.am | 3 +- libfprint/core.c | 1 + libfprint/drivers/aes4000.c | 225 ++++++++++++++++++++++++++++++++++++ libfprint/fp_internal.h | 1 + 5 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 libfprint/drivers/aes4000.c diff --git a/TODO b/TODO index 586e45a..f92bfcd 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,6 @@ DRIVERS ======= Sunplus 895 driver AES3501 driver -AES4000 driver ID Mouse driver Support for 2nd generation MS devices Support for 2nd generation UPEK devices diff --git a/libfprint/Makefile.am b/libfprint/Makefile.am index bdec471..a685774 100644 --- a/libfprint/Makefile.am +++ b/libfprint/Makefile.am @@ -2,8 +2,9 @@ lib_LTLIBRARIES = libfprint.la UPEKTS_SRC = drivers/upekts.c URU4000_SRC = drivers/uru4000.c +AES4000_SRC = drivers/aes4000.c -DRIVER_SRC = $(UPEKTS_SRC) $(URU4000_SRC) +DRIVER_SRC = $(UPEKTS_SRC) $(URU4000_SRC) $(AES4000_SRC) libfprint_la_CFLAGS = -fvisibility=hidden $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(AM_CFLAGS) libfprint_la_LDFLAGS = -version-info @lt_major@:@lt_revision@:@lt_age@ diff --git a/libfprint/core.c b/libfprint/core.c index ff8850a..d6c3632 100644 --- a/libfprint/core.c +++ b/libfprint/core.c @@ -79,6 +79,7 @@ static struct fp_driver * const primitive_drivers[] = { static struct fp_img_driver * const img_drivers[] = { &uru4000_driver, + &aes4000_driver, }; static void register_drivers(void) diff --git a/libfprint/drivers/aes4000.c b/libfprint/drivers/aes4000.c new file mode 100644 index 0000000..cbbcfbf --- /dev/null +++ b/libfprint/drivers/aes4000.c @@ -0,0 +1,225 @@ +/* + * AuthenTec AES4000 driver for libfprint + * Copyright (C) 2007 Daniel Drake + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FP_COMPONENT "aes4000" + +#include + +#include +#include + +#include + +#define CTRL_TIMEOUT 1000 +#define EP_IN (1 | USB_ENDPOINT_IN) +#define EP_OUT (2 | USB_ENDPOINT_OUT) +#define DATA_BUFLEN 0x1259 +#define NR_SUBARRAYS 6 +#define SUBARRAY_LEN 768 + +static int write_reg(struct fp_img_dev *dev, unsigned char reg, + unsigned char value) +{ + unsigned char data[] = { reg, value }; + int r; + + fp_dbg("%02x=%02x", reg, value); + r = usb_bulk_write(dev->udev, EP_OUT, data, sizeof(data), CTRL_TIMEOUT); + if (r < 0) { + fp_err("bulk write error %d", r); + return r; + } else if (r < sizeof(data)) { + fp_err("unexpected short write %d/%d", r, sizeof(data)); + return -EIO; + } + + return 0; +} + +static void process_subarray(unsigned char *src, unsigned char *dst) +{ + int col, row; + int offset = -1; + + for (col = 95; col >= 0; col--) { + for (row = 15; row >= 0; row -= 2) { + unsigned char val = src[++offset]; + dst[(row * 96) + col] = (val & 0x7) * 36; + dst[((row - 1) * 96) + col] = ((val & 0x70) >> 4) * 36; + } + } +} + +static const struct aes4000_regwrite { + unsigned char reg; + unsigned char value; +} init_reqs[] = { + /* master reset */ + { 0x80, 0x01 }, + { 0x80, 0x00 }, + + { 0x81, 0x00 }, + { 0x80, 0x00 }, + + /* scan reset */ + { 0x80, 0x02 }, + { 0x80, 0x00 }, + + /* disable register buffering */ + { 0x80, 0x04 }, + { 0x80, 0x00 }, + + { 0x81, 0x00 }, + /* windows driver reads registers now (81 02) */ + { 0x80, 0x00 }, + { 0x81, 0x00 }, + + /* set excitation bias current: 2mhz drive ring frequency, + * 4V drive ring voltage, 16.5mA excitation bias */ + { 0x82, 0x04 }, + + /* continuously sample drive ring for finger detection, + * 62.50ms debounce delay */ + { 0x83, 0x13 }, + + { 0x84, 0x07 }, /* set calibration resistance to 12 kiloohms */ + { 0x85, 0x3d }, /* set calibration capacitance */ + { 0x86, 0x03 }, /* detect drive voltage */ + { 0x87, 0x01 }, /* set detection frequency to 125khz */ + { 0x88, 0x03 }, /* set column scan period */ + { 0x89, 0x03 }, /* set measure drive */ + { 0x8a, 0x32 }, /* set measure frequency and sense amplifier bias */ + { 0x8b, 0x33 }, /* set matrix pattern */ + { 0x8c, 0x0b }, /* set demodulation phase 1 */ + { 0x8d, 0x04 }, /* set demodulation phase 2 */ + { 0x8e, 0x33 }, /* set sensor gain */ + { 0x8f, 0x03 }, /* set image parameters */ + { 0x90, 0x0f }, /* carrier offset null */ + { 0x91, 0x03 }, /* set A/D reference high */ + { 0x92, 0x03 }, /* set A/D reference low */ + { 0x93, 0x00 }, /* set start row to 0 */ + { 0x94, 0x05 }, /* set end row to 5 */ + { 0x95, 0x00 }, /* set start column to 0 */ + { 0x96, 0x18 }, /* set end column to 24*4=96 */ + { 0x97, 0x04 }, /* data format and thresholds */ + { 0x98, 0x28 }, /* image data control */ + { 0x99, 0x00 }, /* disable general purpose outputs */ + { 0x9a, 0x0b }, /* set initial scan state */ + { 0x9b, 0x00 }, /* clear challenge word bits */ + { 0x9c, 0x00 }, /* clear challenge word bits */ + { 0x9d, 0x09 }, /* set some challenge word bits */ + { 0x9e, 0x53 }, /* clear challenge word bits */ + { 0x9f, 0x6b }, /* set some challenge word bits */ + + { 0x80, 0x00 }, + { 0x81, 0x00 }, + { 0x81, 0x04 }, + { 0x81, 0x00 }, +}; + +static int capture(struct fp_img_dev *dev, gboolean unconditional, + struct fp_img **ret) +{ + int i; + int r; + struct fp_img *img; + unsigned char *data; + unsigned char *ptr; + + for (i = 0; i < ARRAY_SIZE(init_reqs); i++) { + r = write_reg(dev, init_reqs[i].reg, init_reqs[i].value); + if (r < 0) + return r; + } + + img = fpi_img_new_for_imgdev(dev); + data = g_malloc(DATA_BUFLEN); + ptr = data; + + /* See the timeout explanation in the uru4000 driver for the reasoning + * behind this silly loop. */ +retry: + r = usb_bulk_read(dev->udev, EP_IN, data, DATA_BUFLEN, 1000); + if (r == -ETIMEDOUT) + goto retry; + + if (r < 0) { + fp_err("data read failed, error %d", r); + goto err; + } else if (r < DATA_BUFLEN) { + fp_err("short data read (%d)", r); + r = -EIO; + goto err; + } + + for (i = NR_SUBARRAYS - 1; i >= 0; i--) { + fp_dbg("subarray header byte %02x", *ptr); + ptr++; + process_subarray(ptr, img->data + (i * 96 * 16)); + ptr += SUBARRAY_LEN; + } + + img->flags = FP_IMG_COLORS_INVERTED; + *ret = img; + g_free(data); + return 0; +err: + g_free(data); + g_free(img); + return r; +} + +static int dev_init(struct fp_img_dev *dev, unsigned long driver_data) +{ + int r; + + r = usb_claim_interface(dev->udev, 0); + if (r < 0) { + fp_err("could not claim interface 0"); + return r; + } + + return 0; +} + +static void dev_exit(struct fp_img_dev *dev) +{ + usb_release_interface(dev->udev, 0); +} + +static const struct usb_id id_table[] = { + { .vendor = 0x08ff, .product = 0x5501 }, + { 0, 0, 0, }, +}; + +struct fp_img_driver aes4000_driver = { + .driver = { + .name = FP_COMPONENT, + .full_name = "AuthenTec AES4000", + .id_table = id_table, + }, + .flags = 0, + .img_height = 96, + .img_width = 96, + + .init = dev_init, + .exit = dev_exit, + .capture = capture, +}; + diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h index 7a2b58a..32ae1c5 100644 --- a/libfprint/fp_internal.h +++ b/libfprint/fp_internal.h @@ -139,6 +139,7 @@ struct fp_img_driver { extern struct fp_driver upekts_driver; extern struct fp_img_driver uru4000_driver; +extern struct fp_img_driver aes4000_driver; void fpi_img_driver_setup(struct fp_img_driver *idriver);