From c7670b28f607e90369ea3ec065f199ed6a52072c Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Sun, 25 Nov 2012 20:47:01 +0300 Subject: [PATCH 5/9] lib: add AES1660/AES2660 common routines --- configure.ac | 6 + libfprint/Makefile.am | 5 + libfprint/drivers/aesx660.c | 637 ++++++++++++++++++++++++++++++++++++++++++++ libfprint/drivers/aesx660.h | 117 ++++++++ 4 files changed, 765 insertions(+) create mode 100644 libfprint/drivers/aesx660.c create mode 100644 libfprint/drivers/aesx660.h diff --git a/configure.ac b/configure.ac index 66806df..43d19a3 100644 --- a/configure.ac +++ b/configure.ac @@ -121,6 +121,7 @@ AM_CONDITIONAL([ENABLE_AES2501], [test "$enable_aes2501" = "yes"]) AM_CONDITIONAL([ENABLE_AES2550], [test "$enable_aes2550" = "yes"]) AM_CONDITIONAL([ENABLE_AES4000], [test "$enable_aes4000" = "yes"]) AM_CONDITIONAL([REQUIRE_AESLIB], [test "$require_aeslib" = "yes"]) +AM_CONDITIONAL([REQUIRE_AESX660], [test "$require_aesX660" = "yes"]) AM_CONDITIONAL([ENABLE_VFS101], [test "$enable_vfs101" = "yes"]) AM_CONDITIONAL([ENABLE_VFS301], [test "$enable_vfs301" = "yes"]) @@ -325,6 +326,11 @@ if test x$require_aeslib != xno ; then else AC_MSG_NOTICE([ aeslib helper functions disabled]) fi +if test x$require_aesX660 != xno ; then + AC_MSG_NOTICE([** aesX660 common routines enabled]) +else + AC_MSG_NOTICE([ aesX660 common routines disabled]) +fi AC_CONFIG_FILES([libfprint.pc] [Makefile] [libfprint/Makefile] [examples/Makefile] [doc/Makefile]) AC_OUTPUT diff --git a/libfprint/Makefile.am b/libfprint/Makefile.am index 7c5f182..aa32357 100644 --- a/libfprint/Makefile.am +++ b/libfprint/Makefile.am @@ -31,6 +31,7 @@ EXTRA_DIST = \ $(VFS101_SRC) \ $(VFS301_SRC) \ aeslib.c aeslib.h \ + aesx660.c aesx660.h \ imagemagick.c \ gdkpixbuf.c \ 60-fprint-autosuspend.rules @@ -158,6 +159,10 @@ if REQUIRE_AESLIB OTHER_SRC += aeslib.c aeslib.h endif +if REQUIRE_AESX660 +OTHER_SRC += drivers/aesx660.c drivers/aesx660.h +endif + libfprint_la_SOURCES = \ fp_internal.h \ async.c \ diff --git a/libfprint/drivers/aesx660.c b/libfprint/drivers/aesx660.c new file mode 100644 index 0000000..ff4f50c --- /dev/null +++ b/libfprint/drivers/aesx660.c @@ -0,0 +1,637 @@ +/* + * AuthenTec AES1660/AES2660 common routines + * Copyright (C) 2007-2008 Daniel Drake + * Copyright (C) 2007 Cyrille Bagard + * Copyright (C) 2007-2008,2012 Vasily Khoruzhick + * + * Based on AES2550 driver + * + * 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 "aesX660" + +#include + +#include +#include + +#include + +#include +#include + +#include "aesx660.h" + +static void start_capture(struct fp_img_dev *dev); +static void complete_deactivation(struct fp_img_dev *dev); + +#define EP_IN (1 | LIBUSB_ENDPOINT_IN) +#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT) +#define BULK_TIMEOUT 4000 +#define FRAME_HEIGHT 8 + +#define min(a, b) (((a) < (b)) ? (a) : (b)) + +static void aesX660_send_cmd_timeout(struct fpi_ssm *ssm, const unsigned char *cmd, + size_t cmd_len, libusb_transfer_cb_fn callback, int timeout) +{ + struct fp_img_dev *dev = ssm->priv; + struct libusb_transfer *transfer = libusb_alloc_transfer(0); + int r; + + if (!transfer) { + fpi_ssm_mark_aborted(ssm, -ENOMEM); + return; + } + + libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, + (unsigned char *)cmd, cmd_len, + callback, ssm, timeout); + r = libusb_submit_transfer(transfer); + if (r < 0) { + fp_dbg("failed to submit transfer\n"); + libusb_free_transfer(transfer); + fpi_ssm_mark_aborted(ssm, -ENOMEM); + } +} + +static void aesX660_send_cmd(struct fpi_ssm *ssm, const unsigned char *cmd, + size_t cmd_len, libusb_transfer_cb_fn callback) +{ + return aesX660_send_cmd_timeout(ssm, cmd, cmd_len, callback, BULK_TIMEOUT); +} + +static void aesX660_read_response(struct fpi_ssm *ssm, size_t buf_len, + libusb_transfer_cb_fn callback) +{ + struct fp_img_dev *dev = ssm->priv; + struct libusb_transfer *transfer = libusb_alloc_transfer(0); + unsigned char *data; + int r; + + if (!transfer) { + fpi_ssm_mark_aborted(ssm, -ENOMEM); + return; + } + + data = g_malloc(buf_len); + libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, + data, buf_len, + callback, ssm, BULK_TIMEOUT); + + r = libusb_submit_transfer(transfer); + if (r < 0) { + fp_dbg("Failed to submit rx transfer: %d\n", r); + g_free(data); + libusb_free_transfer(transfer); + fpi_ssm_mark_aborted(ssm, r); + } +} + +static void aesX660_send_cmd_cb(struct libusb_transfer *transfer) +{ + struct fpi_ssm *ssm = transfer->user_data; + + if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && + (transfer->length == transfer->actual_length)) { + fpi_ssm_next_state(ssm); + } else { + fp_dbg("tx transfer status: %d, actual_len: %.4x\n", + transfer->status, transfer->actual_length); + fpi_ssm_mark_aborted(ssm, -EIO); + } + libusb_free_transfer(transfer); +} + +static void aesX660_read_calibrate_data_cb(struct libusb_transfer *transfer) +{ + struct fpi_ssm *ssm = transfer->user_data; + unsigned char *data = transfer->buffer; + + if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || + (transfer->length != transfer->actual_length)) { + fpi_ssm_mark_aborted(ssm, -EIO); + goto out; + } + /* Calibrate response was read correctly? */ + if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE) { + fp_dbg("Bogus calibrate response: %.2x\n", data[0]); + fpi_ssm_mark_aborted(ssm, -EPROTO); + goto out; + } + + fpi_ssm_next_state(ssm); +out: + g_free(transfer->buffer); + libusb_free_transfer(transfer); +} + +/****** FINGER PRESENCE DETECTION ******/ + +enum finger_det_states { + FINGER_DET_SEND_LED_CMD, + FINGER_DET_SEND_FD_CMD, + FINGER_DET_READ_FD_DATA, + FINGER_DET_SET_IDLE, + FINGER_DET_NUM_STATES, +}; + +static void finger_det_read_fd_data_cb(struct libusb_transfer *transfer) +{ + struct fpi_ssm *ssm = transfer->user_data; + struct fp_img_dev *dev = ssm->priv; + struct aesX660_dev *aesdev = dev->priv; + unsigned char *data = transfer->buffer; + + aesdev->fd_data_transfer = NULL; + + if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { + fp_dbg("Cancelling transfer...\n"); + fpi_ssm_next_state(ssm); + goto out; + } + + if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || + (transfer->length != transfer->actual_length)) { + fp_dbg("Failed to read FD data\n"); + fpi_ssm_mark_aborted(ssm, -EIO); + goto out; + } + + if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE) { + fp_dbg("Bogus FD response: %.2x\n", data[0]); + fpi_ssm_mark_aborted(ssm, -EPROTO); + goto out; + } + + if (data[AESX660_FINGER_PRESENT_OFFSET] == AESX660_FINGER_PRESENT || aesdev->deactivating) { + /* Finger present or we're deactivating... */ + fpi_ssm_next_state(ssm); + } else { + fp_dbg("Wait for finger returned %.2x as result\n", + data[AESX660_FINGER_PRESENT_OFFSET]); + fpi_ssm_jump_to_state(ssm, FINGER_DET_SEND_FD_CMD); + } +out: + g_free(data); + libusb_free_transfer(transfer); +} + +static void finger_det_set_idle_cmd_cb(struct libusb_transfer *transfer) +{ + struct fpi_ssm *ssm = transfer->user_data; + + if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && + (transfer->length == transfer->actual_length)) { + fpi_ssm_mark_completed(ssm); + } else { + fpi_ssm_mark_aborted(ssm, -EIO); + } + libusb_free_transfer(transfer); +} + +static void finger_det_sm_complete(struct fpi_ssm *ssm) +{ + struct fp_img_dev *dev = ssm->priv; + struct aesX660_dev *aesdev = dev->priv; + int err = ssm->error; + + fp_dbg("Finger detection completed"); + fpi_imgdev_report_finger_status(dev, TRUE); + fpi_ssm_free(ssm); + + if (aesdev->deactivating) + complete_deactivation(dev); + else if (err) + fpi_imgdev_session_error(dev, err); + else { + fpi_imgdev_report_finger_status(dev, TRUE); + start_capture(dev); + } +} + +static void finger_det_run_state(struct fpi_ssm *ssm) +{ + switch (ssm->cur_state) { + case FINGER_DET_SEND_LED_CMD: + aesX660_send_cmd(ssm, led_blink_cmd, sizeof(led_blink_cmd), + aesX660_send_cmd_cb); + break; + case FINGER_DET_SEND_FD_CMD: + aesX660_send_cmd_timeout(ssm, wait_for_finger_cmd, sizeof(wait_for_finger_cmd), + aesX660_send_cmd_cb, 0); + break; + case FINGER_DET_READ_FD_DATA: + /* Should return 4 byte of response */ + aesX660_read_response(ssm, 4, finger_det_read_fd_data_cb); + break; + case FINGER_DET_SET_IDLE: + aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd), + finger_det_set_idle_cmd_cb); + break; + } +} + +static void start_finger_detection(struct fp_img_dev *dev) +{ + struct fpi_ssm *ssm; + struct aesX660_dev *aesdev = dev->priv; + + if (aesdev->deactivating) { + complete_deactivation(dev); + return; + } + + ssm = fpi_ssm_new(dev->dev, finger_det_run_state, FINGER_DET_NUM_STATES); + ssm->priv = dev; + fpi_ssm_start(ssm, finger_det_sm_complete); +} + +/****** CAPTURE ******/ + +enum capture_states { + CAPTURE_SEND_LED_CMD, + CAPTURE_SEND_CAPTURE_CMD, + CAPTURE_READ_STRIPE_DATA, + CAPTURE_SET_IDLE, + CAPTURE_NUM_STATES, +}; + +/* Returns number of processed bytes */ +static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data) +{ + unsigned char *stripdata; + struct fp_img_dev *dev = ssm->priv; + struct aesX660_dev *aesdev = dev->priv; + + stripdata = g_malloc(aesdev->frame_width * FRAME_HEIGHT / 2); /* 4 bits per pixel */ + if (!stripdata) { + fpi_ssm_mark_aborted(ssm, -ENOMEM); + return 1; + } + + fp_dbg("Processing frame %.2x %.2x", data[AESX660_IMAGE_OK_OFFSET], + data[AESX660_LAST_FRAME_OFFSET]); + + if (data[AESX660_IMAGE_OK_OFFSET] == AESX660_IMAGE_OK) { + memcpy(stripdata, data + AESX660_IMAGE_OFFSET, aesdev->frame_width * FRAME_HEIGHT / 2); + + aesdev->strips = g_slist_prepend(aesdev->strips, stripdata); + aesdev->strips_len++; + return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT); + } else { + return 0; + } + +} + +static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer) +{ + struct fpi_ssm *ssm = transfer->user_data; + struct fp_img_dev *dev = ssm->priv; + struct aesX660_dev *aesdev = dev->priv; + + if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && + (transfer->length == transfer->actual_length)) { + struct fp_img *img, *tmp; + + aesdev->strips = g_slist_reverse(aesdev->strips); + tmp = aes_assemble(aesdev->strips, aesdev->strips_len, + aesdev->frame_width, FRAME_HEIGHT); + g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL); + g_slist_free(aesdev->strips); + aesdev->strips = NULL; + aesdev->strips_len = 0; + if (aesdev->h_scale_factor > 1) { + img = fpi_im_resize(tmp, aesdev->h_scale_factor, 1); + fp_img_free(tmp); + } else { + img = tmp; + tmp = NULL; + } + fpi_imgdev_image_captured(dev, img); + fpi_imgdev_report_finger_status(dev, FALSE); + fpi_ssm_mark_completed(ssm); + } else { + fpi_ssm_mark_aborted(ssm, -EIO); + } + libusb_free_transfer(transfer); +} + +static void capture_read_stripe_data_cb(struct libusb_transfer *transfer) +{ + struct fpi_ssm *ssm = transfer->user_data; + struct fp_img_dev *dev = ssm->priv; + struct aesX660_dev *aesdev = dev->priv; + unsigned char *data = transfer->buffer; + int finger_missing = 0; + size_t copied, actual_len = transfer->actual_length; + + if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { + fpi_ssm_mark_aborted(ssm, -EIO); + goto out; + } + + fp_dbg("Got %d bytes of data", actual_len); + do { + copied = min(aesdev->buffer_max - aesdev->buffer_size, actual_len); + memcpy(aesdev->buffer + aesdev->buffer_size, + data, + copied); + actual_len -= copied; + data += copied; + aesdev->buffer_size += copied; + fp_dbg("Copied %.4x bytes into internal buffer", + copied); + if (aesdev->buffer_size == aesdev->buffer_max) { + if (aesdev->buffer_max == AESX660_HEADER_SIZE) { + aesdev->buffer_max = aesdev->buffer[AESX660_RESPONSE_SIZE_LSB_OFFSET] + + (aesdev->buffer[AESX660_RESPONSE_SIZE_MSB_OFFSEt] << 8) + AESX660_HEADER_SIZE; + fp_dbg("Got frame, type %.2x size %.4x", + aesdev->buffer[AESX660_RESPONSE_TYPE_OFFSET], + aesdev->buffer_max); + continue; + } else { + finger_missing |= process_stripe_data(ssm, aesdev->buffer); + aesdev->buffer_max = AESX660_HEADER_SIZE; + aesdev->buffer_size = 0; + } + } + } while (actual_len); + + fp_dbg("finger %s\n", finger_missing ? "missing" : "present"); + + if (finger_missing) { + fpi_ssm_next_state(ssm); + } else { + fpi_ssm_jump_to_state(ssm, CAPTURE_READ_STRIPE_DATA); + } +out: + g_free(transfer->buffer); + libusb_free_transfer(transfer); +} + +static void capture_run_state(struct fpi_ssm *ssm) +{ + struct fp_img_dev *dev = ssm->priv; + struct aesX660_dev *aesdev = dev->priv; + + switch (ssm->cur_state) { + case CAPTURE_SEND_LED_CMD: + aesX660_send_cmd(ssm, led_solid_cmd, sizeof(led_solid_cmd), + aesX660_send_cmd_cb); + break; + case CAPTURE_SEND_CAPTURE_CMD: + aesdev->buffer_size = 0; + aesdev->buffer_max = AESX660_HEADER_SIZE; + aesX660_send_cmd(ssm, aesdev->start_imaging_cmd, + aesdev->start_imaging_cmd_len, + aesX660_send_cmd_cb); + break; + case CAPTURE_READ_STRIPE_DATA: + aesX660_read_response(ssm, AESX660_BULK_TRANSFER_SIZE, + capture_read_stripe_data_cb); + break; + case CAPTURE_SET_IDLE: + fp_dbg("Got %d frames\n", aesdev->strips_len); + aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd), + capture_set_idle_cmd_cb); + break; + } +} + +static void capture_sm_complete(struct fpi_ssm *ssm) +{ + struct fp_img_dev *dev = ssm->priv; + struct aesX660_dev *aesdev = dev->priv; + int err = ssm->error; + + fp_dbg("Capture completed"); + fpi_ssm_free(ssm); + + if (aesdev->deactivating) + complete_deactivation(dev); + else if (err) + fpi_imgdev_session_error(dev, err); + else + start_finger_detection(dev); +} + +static void start_capture(struct fp_img_dev *dev) +{ + struct aesX660_dev *aesdev = dev->priv; + struct fpi_ssm *ssm; + + if (aesdev->deactivating) { + complete_deactivation(dev); + return; + } + + ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES); + fp_dbg(""); + ssm->priv = dev; + fpi_ssm_start(ssm, capture_sm_complete); +} + +/****** INITIALIZATION/DEINITIALIZATION ******/ + +enum activate_states { + ACTIVATE_SET_IDLE, + ACTIVATE_SEND_READ_ID_CMD, + ACTIVATE_READ_ID, + ACTIVATE_SEND_CALIBRATE_CMD, + ACTIVATE_READ_CALIBRATE_DATA, + ACTIVATE_SEND_INIT_CMD, + ACTIVATE_READ_INIT_RESPONSE, + ACTIVATE_NUM_STATES, +}; + +static void activate_read_id_cb(struct libusb_transfer *transfer) +{ + struct fpi_ssm *ssm = transfer->user_data; + struct fp_img_dev *dev = ssm->priv; + struct aesX660_dev *aesdev = dev->priv; + unsigned char *data = transfer->buffer; + + if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || + (transfer->length != transfer->actual_length)) { + fp_dbg("read_id cmd failed\n"); + fpi_ssm_mark_aborted(ssm, -EIO); + goto out; + } + /* ID was read correctly */ + if (data[0] == 0x07) { + fp_dbg("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x\n", + data[4], data[3], data[5], data[6], data[7]); + } else { + fp_dbg("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]); + fpi_ssm_mark_aborted(ssm, -EPROTO); + goto out; + } + + switch (aesdev->init_seq_idx) { + case 0: + aesdev->init_seq = aesdev->init_seqs[0]; + aesdev->init_seq_len = aesdev->init_seqs_len[0]; + aesdev->init_seq_idx = 1; + aesdev->init_cmd_idx = 0; + /* Do calibration only after 1st init sequence */ + fpi_ssm_jump_to_state(ssm, ACTIVATE_SEND_INIT_CMD); + break; + case 1: + aesdev->init_seq = aesdev->init_seqs[1]; + aesdev->init_seq_len = aesdev->init_seqs_len[1]; + aesdev->init_seq_idx = 2; + aesdev->init_cmd_idx = 0; + fpi_ssm_next_state(ssm); + break; + default: + fp_dbg("Failed to init device! init status: %.2x\n", data[7]); + fpi_ssm_mark_aborted(ssm, -EPROTO); + break; + + } + +out: + g_free(transfer->buffer); + libusb_free_transfer(transfer); +} + +static void activate_read_init_cb(struct libusb_transfer *transfer) +{ + struct fpi_ssm *ssm = transfer->user_data; + struct fp_img_dev *dev = ssm->priv; + struct aesX660_dev *aesdev = dev->priv; + unsigned char *data = transfer->buffer; + + fp_dbg("read_init_cb\n"); + + if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) || + (transfer->length != transfer->actual_length)) { + fp_dbg("read_init transfer status: %d, actual_len: %d\n", transfer->status, transfer->actual_length); + fpi_ssm_mark_aborted(ssm, -EIO); + goto out; + } + /* ID was read correctly */ + if (data[0] != 0x42 || data[3] != 0x01) { + fp_dbg("Bogus read init response: %.2x %.2x\n", data[0], + data[3]); + fpi_ssm_mark_aborted(ssm, -EPROTO); + goto out; + } + aesdev->init_cmd_idx++; + if (aesdev->init_cmd_idx == aesdev->init_seq_len) { + if (aesdev->init_seq_idx < 2) + fpi_ssm_jump_to_state(ssm, ACTIVATE_SEND_READ_ID_CMD); + else + fpi_ssm_mark_completed(ssm); + goto out; + } + + fpi_ssm_jump_to_state(ssm, ACTIVATE_SEND_INIT_CMD); +out: + g_free(transfer->buffer); + libusb_free_transfer(transfer); +} + +static void activate_run_state(struct fpi_ssm *ssm) +{ + struct fp_img_dev *dev = ssm->priv; + struct aesX660_dev *aesdev = dev->priv; + + switch (ssm->cur_state) { + case ACTIVATE_SET_IDLE: + aesdev->init_seq_idx = 0; + fp_dbg("Activate: set idle\n"); + aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd), + aesX660_send_cmd_cb); + break; + case ACTIVATE_SEND_READ_ID_CMD: + fp_dbg("Activate: read ID\n"); + aesX660_send_cmd(ssm, read_id_cmd, sizeof(read_id_cmd), + aesX660_send_cmd_cb); + break; + case ACTIVATE_READ_ID: + /* Should return 8-byte response */ + aesX660_read_response(ssm, 8, activate_read_id_cb); + break; + case ACTIVATE_SEND_INIT_CMD: + fp_dbg("Activate: send init seq #%d cmd #%d\n", + aesdev->init_seq_idx, + aesdev->init_cmd_idx); + aesX660_send_cmd(ssm, + aesdev->init_seq[aesdev->init_cmd_idx].cmd, + aesdev->init_seq[aesdev->init_cmd_idx].len, + aesX660_send_cmd_cb); + break; + case ACTIVATE_READ_INIT_RESPONSE: + fp_dbg("Activate: read init response\n"); + /* Should return 4-byte response */ + aesX660_read_response(ssm, 4, activate_read_init_cb); + break; + case ACTIVATE_SEND_CALIBRATE_CMD: + aesX660_send_cmd(ssm, calibrate_cmd, sizeof(calibrate_cmd), + aesX660_send_cmd_cb); + break; + case ACTIVATE_READ_CALIBRATE_DATA: + /* Should return 4-byte response */ + aesX660_read_response(ssm, 4, aesX660_read_calibrate_data_cb); + break; + } +} + +static void activate_sm_complete(struct fpi_ssm *ssm) +{ + struct fp_img_dev *dev = ssm->priv; + int err = ssm->error; + fp_dbg("status %d", err); + fpi_imgdev_activate_complete(dev, err); + fpi_ssm_free(ssm); + + if (!err) + start_finger_detection(dev); +} + +int aesX660_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) +{ + struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state, + ACTIVATE_NUM_STATES); + ssm->priv = dev; + fpi_ssm_start(ssm, activate_sm_complete); + return 0; +} + +void aesX660_dev_deactivate(struct fp_img_dev *dev) +{ + struct aesX660_dev *aesdev = dev->priv; + + if (aesdev->fd_data_transfer) + libusb_cancel_transfer(aesdev->fd_data_transfer); + + aesdev->deactivating = TRUE; +} + +static void complete_deactivation(struct fp_img_dev *dev) +{ + struct aesX660_dev *aesdev = dev->priv; + fp_dbg(""); + + aesdev->deactivating = FALSE; + g_slist_free(aesdev->strips); + aesdev->strips = NULL; + aesdev->strips_len = 0; + fpi_imgdev_deactivate_complete(dev); +} diff --git a/libfprint/drivers/aesx660.h b/libfprint/drivers/aesx660.h new file mode 100644 index 0000000..b53ad51 --- /dev/null +++ b/libfprint/drivers/aesx660.h @@ -0,0 +1,117 @@ +/* + * AuthenTec AES1660/AES2660 common definitions + * Copyright (c) 2012 Vasily Khoruzhick + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __AESX660_H +#define __AESX660_H + +#define AESX660_HEADER_SIZE 3 +#define AESX660_RESPONSE_TYPE_OFFSET 0x00 +#define AESX660_RESPONSE_SIZE_LSB_OFFSET 0x01 +#define AESX660_RESPONSE_SIZE_MSB_OFFSEt 0x02 + +#define AESX660_CALIBRATE_RESPONSE 0x06 +#define AESX660_FINGER_DET_RESPONSE 0x40 +#define AESX660_FINGER_PRESENT_OFFSET 0x03 +#define AESX660_FINGER_PRESENT 0x01 + +#define AESX660_IMAGE_OK_OFFSET 0x03 +#define AESX660_IMAGE_OK 0x0d +#define AESX660_LAST_FRAME_OFFSET 0x04 +#define AESX660_LAST_FRAME_BIT 0x01 + +#define AESX660_IMAGE_OFFSET 43 +#define AESX660_BULK_TRANSFER_SIZE 4096 + +struct aesX660_dev { + GSList *strips; + size_t strips_len; + gboolean deactivating; + struct aesX660_cmd *init_seq; + size_t init_seq_len; + unsigned int init_cmd_idx; + unsigned int init_seq_idx; + struct libusb_transfer *fd_data_transfer; + unsigned char *buffer; + size_t buffer_size; + size_t buffer_max; + + /* Device-specific stuff */ + int h_scale_factor; + struct aesX660_cmd *init_seqs[2]; + size_t init_seqs_len[2]; + unsigned char *start_imaging_cmd; + size_t start_imaging_cmd_len; + unsigned int frame_width; +}; + +struct aesX660_cmd { + const unsigned char *cmd; + size_t len; +}; + +/* 0x77 cmd seems to control LED, this sequence + * makes LED blink + */ +static const unsigned char led_blink_cmd[] = { +0x77, 0x18, 0x00, +0x00, 0x3f, 0x00, 0xff, 0x00, +0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00, +0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xf3, +0x01, 0x00, 0x7f +}; + +/* This sequence makes LED light solid + */ +static const unsigned char led_solid_cmd[] = { +0x77, 0x18, 0x00, 0x00, 0x3f, 0x00, 0xff, 0x00, +0x01, 0x01, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00, +0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7f +}; + +static const unsigned char wait_for_finger_cmd[] = { +0x20, +0x40, 0x04, 0x00, 0x02, 0x1e, 0x00, 0x32 +}; + +/* 0x40 cmd response + * +static const unsigned char pkt1371[] = { +0x40, 0x01, 0x00, 0x01 +}; +*/ + +static const unsigned char set_idle_cmd[] = { + 0x0d, /* Reset or "set idle"? */ +}; + +static const unsigned char read_id_cmd[] = { + 0x44, 0x02, 0x00, 0x08, 0x00, /* Max transfer size is 8 */ + 0x07, /* Read ID? */ +}; + +static const unsigned char calibrate_cmd[] = { + 0x44, 0x02, 0x00, 0x04, 0x00, + 0x06, +}; + +int aesX660_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state); +void aesX660_dev_deactivate(struct fp_img_dev *dev); + +#endif -- 1.8.0