diff options
Diffstat (limited to 'testing/libfprint')
5 files changed, 177 insertions, 898 deletions
diff --git a/testing/libfprint/0001-uru4000-fix-race-condition-on-waiting-power-up-irq.patch b/testing/libfprint/0001-uru4000-fix-race-condition-on-waiting-power-up-irq.patch new file mode 100644 index 0000000000..88e20518c2 --- /dev/null +++ b/testing/libfprint/0001-uru4000-fix-race-condition-on-waiting-power-up-irq.patch @@ -0,0 +1,87 @@ +From 7e1646c382bbd6dc21a167bf7f0e45afa5ea217e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> +Date: Tue, 4 Dec 2012 10:50:30 +0200 +Subject: [PATCH 1/3] uru4000: fix race condition on waiting power up irq + +It can come before we finish reading the status register on some +cases. Arm the irq handler early, and fix the state machine to +handle early irq properly. + +https://bugs.freedesktop.org/show_bug.cgi?id=57834 +--- + libfprint/drivers/uru4000.c | 31 ++++++++++++++++++++----------- + 1 file changed, 20 insertions(+), 11 deletions(-) + +diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c +index 541245a..07e26a4 100644 +--- a/libfprint/drivers/uru4000.c ++++ b/libfprint/drivers/uru4000.c +@@ -994,16 +994,19 @@ static void init_scanpwr_irq_cb(struct fp_img_dev *dev, int status, + uint16_t type, void *user_data) + { + struct fpi_ssm *ssm = user_data; ++ struct uru4k_dev *urudev = dev->priv; + + if (status) + fpi_ssm_mark_aborted(ssm, status); + else if (type != IRQDATA_SCANPWR_ON) + fp_dbg("ignoring interrupt"); +- else if (ssm->cur_state != INIT_AWAIT_SCAN_POWER) +- fp_err("ignoring scanpwr interrupt due to being in wrong state %d", +- ssm->cur_state); +- else ++ else if (ssm->cur_state != INIT_AWAIT_SCAN_POWER) { ++ fp_dbg("early scanpwr interrupt"); ++ urudev->scanpwr_irq_timeouts = -1; ++ } else { ++ fp_dbg("late scanpwr interrupt"); + fpi_ssm_next_state(ssm); ++ } + } + + static void init_scanpwr_timeout(void *user_data) +@@ -1053,14 +1056,21 @@ static void init_run_state(struct fpi_ssm *ssm) + fpi_ssm_next_state(ssm); + break; + case INIT_POWERUP: ; ++ if (!IRQ_HANDLER_IS_RUNNING(urudev)) { ++ fpi_ssm_mark_aborted(ssm, -EIO); ++ break; ++ } ++ urudev->irq_cb_data = ssm; ++ urudev->irq_cb = init_scanpwr_irq_cb; ++ + struct fpi_ssm *powerupsm = fpi_ssm_new(dev->dev, powerup_run_state, + POWERUP_NUM_STATES); + powerupsm->priv = dev; + fpi_ssm_start_subsm(ssm, powerupsm); + break; + case INIT_AWAIT_SCAN_POWER: +- if (!IRQ_HANDLER_IS_RUNNING(urudev)) { +- fpi_ssm_mark_aborted(ssm, -EIO); ++ if (urudev->scanpwr_irq_timeouts < 0) { ++ fpi_ssm_next_state(ssm); + break; + } + +@@ -1073,13 +1083,12 @@ static void init_run_state(struct fpi_ssm *ssm) + fpi_ssm_mark_aborted(ssm, -ETIME); + break; + } +- +- urudev->irq_cb_data = ssm; +- urudev->irq_cb = init_scanpwr_irq_cb; + break; + case INIT_DONE: +- fpi_timeout_cancel(urudev->scanpwr_irq_timeout); +- urudev->scanpwr_irq_timeout = NULL; ++ if (urudev->scanpwr_irq_timeout) { ++ fpi_timeout_cancel(urudev->scanpwr_irq_timeout); ++ urudev->scanpwr_irq_timeout = NULL; ++ } + urudev->irq_cb_data = NULL; + urudev->irq_cb = NULL; + fpi_ssm_next_state(ssm); +-- +1.8.0.1 + diff --git a/testing/libfprint/0002-uru4000-fix-cancelling-of-imaging-from-error-callbac.patch b/testing/libfprint/0002-uru4000-fix-cancelling-of-imaging-from-error-callbac.patch new file mode 100644 index 0000000000..fc5d3f491d --- /dev/null +++ b/testing/libfprint/0002-uru4000-fix-cancelling-of-imaging-from-error-callbac.patch @@ -0,0 +1,45 @@ +From 045d3c92c22cfc12acd3fe1b2d43bab819758c98 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> +Date: Mon, 3 Dec 2012 09:51:27 +0200 +Subject: [PATCH 2/3] uru4000: fix cancelling of imaging from error callback + +Call error callback before resetting img_transfer to NULL. This +variable is internally used to detect if we are still in imaging +loop and the call to execute_state_change() needs to be postponed. +Since this is the final thing imaging_complete() we can't reset +img_transfer until just before this call. + +https://bugs.freedesktop.org/show_bug.cgi?id=57829 +--- + libfprint/drivers/uru4000.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c +index 07e26a4..ccaa87f 100644 +--- a/libfprint/drivers/uru4000.c ++++ b/libfprint/drivers/uru4000.c +@@ -789,15 +789,18 @@ static void imaging_complete(struct fpi_ssm *ssm) + int r = ssm->error; + fpi_ssm_free(ssm); + ++ /* Report error before exiting imaging loop - the error handler ++ * can request state change, which needs to be postponed to end of ++ * this function. */ ++ if (r) ++ fpi_imgdev_session_error(dev, r); ++ + g_free(urudev->img_data); + urudev->img_data = NULL; + + libusb_free_transfer(urudev->img_transfer); + urudev->img_transfer = NULL; + +- if (r) +- fpi_imgdev_session_error(dev, r); +- + r = execute_state_change(dev); + if (r) + fpi_imgdev_session_error(dev, r); +-- +1.8.0.1 + diff --git a/testing/libfprint/0003-imgdev-fix-cancelling-of-enrollment-from-stage_compl.patch b/testing/libfprint/0003-imgdev-fix-cancelling-of-enrollment-from-stage_compl.patch new file mode 100644 index 0000000000..303090c7ea --- /dev/null +++ b/testing/libfprint/0003-imgdev-fix-cancelling-of-enrollment-from-stage_compl.patch @@ -0,0 +1,34 @@ +From 72bf2bc90e5e5fccc10f77859dbba666d055df9f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> +Date: Mon, 3 Dec 2012 09:57:25 +0200 +Subject: [PATCH 3/3] imgdev: fix cancelling of enrollment from stage_completed + callback + +Re-check device state after fpi_drvcb_enroll_stage_completed(). +If enrollment was cancelled after non-completing stage, we must +not restart acquire as it would confuse the internal state machine. + +https://bugs.freedesktop.org/show_bug.cgi?id=57829 +--- + libfprint/imgdev.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/libfprint/imgdev.c b/libfprint/imgdev.c +index 14e41ae..1ed3f6d 100644 +--- a/libfprint/imgdev.c ++++ b/libfprint/imgdev.c +@@ -145,7 +145,10 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev, + case IMG_ACTION_ENROLL: + fp_dbg("reporting enroll result"); + fpi_drvcb_enroll_stage_completed(imgdev->dev, r, data, img); +- if (r > 0 && r != FP_ENROLL_COMPLETE && r != FP_ENROLL_FAIL) { ++ /* the callback can cancel enrollment, so recheck current ++ * action and the status to see if retry is needed */ ++ if (imgdev->action == IMG_ACTION_ENROLL && ++ r > 0 && r != FP_ENROLL_COMPLETE && r != FP_ENROLL_FAIL) { + imgdev->action_result = 0; + imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON; + dev_change_state(imgdev, IMG_ACQUIRE_STATE_AWAIT_FINGER_ON); +-- +1.8.0.1 + diff --git a/testing/libfprint/APKBUILD b/testing/libfprint/APKBUILD index 099116e29c..879c91169d 100644 --- a/testing/libfprint/APKBUILD +++ b/testing/libfprint/APKBUILD @@ -1,8 +1,8 @@ # Contributor: Timo Teräs <timo.teras@iki.fi> # Maintainer: Timo Teräs <timo.teras@iki.fi> pkgname=libfprint -pkgver=0.4.0 -pkgrel=1 +pkgver=0.5.0 +pkgrel=0 pkgdesc="fingerprint reader and identification library" url="http://www.freedesktop.org/wiki/Software/fprint/libfprint" arch="all" @@ -12,8 +12,11 @@ depends_dev="libusb-dev" makedepends="$depends_dev nss-dev glib-dev gdk-pixbuf-dev" install="" subpackages="$pkgname-dev" -source="http://people.freedesktop.org/~hadess/libfprint-$pkgver.tar.bz2 - uru4500-support.patch" +source="http://people.freedesktop.org/~hadess/libfprint-$pkgver.tar.xz + 0001-uru4000-fix-race-condition-on-waiting-power-up-irq.patch + 0002-uru4000-fix-cancelling-of-imaging-from-error-callbac.patch + 0003-imgdev-fix-cancelling-of-enrollment-from-stage_compl.patch + " _builddir="$srcdir"/libfprint-$pkgver prepare() { @@ -46,5 +49,7 @@ package() { rm -f "$pkgdir"/usr/lib/*.la } -md5sums="844b7618a095d247c27eedce99313ed2 libfprint-0.4.0.tar.bz2 -237ab2988c4b9523c09a75d04cce931f uru4500-support.patch" +md5sums="65d118369a47a93be623816f54cdb847 libfprint-0.5.0.tar.xz +2a184777defbdb90a8c0ef32f6246b49 0001-uru4000-fix-race-condition-on-waiting-power-up-irq.patch +8e5f6cd2a4967a818729f6fb7e992881 0002-uru4000-fix-cancelling-of-imaging-from-error-callbac.patch +9c3e6511cd4ac0cdc889e170ed22d954 0003-imgdev-fix-cancelling-of-enrollment-from-stage_compl.patch" diff --git a/testing/libfprint/uru4500-support.patch b/testing/libfprint/uru4500-support.patch deleted file mode 100644 index 7cf7db636f..0000000000 --- a/testing/libfprint/uru4500-support.patch +++ /dev/null @@ -1,892 +0,0 @@ -From 401e0912400d7274f163302baed9af63b4d3bbb2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi> -Date: Wed, 26 Sep 2012 13:41:13 +0300 -Subject: [PATCH] lib: Add support for DigitalPersona URU4500 - -By adding native encryption support, rather than poking at -the firmware to disable it. - -This also makes the URU4000B use native encryption. - -https://bugs.freedesktop.org/show_bug.cgi?id=55351 ---- - libfprint/drivers/uru4000.c | 579 +++++++++++++++++++++++++------------------- - libfprint/fp_internal.h | 2 + - 2 files changed, 333 insertions(+), 248 deletions(-) - -diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c -index 0dbea96..f42b609 100644 ---- a/libfprint/drivers/uru4000.c -+++ b/libfprint/drivers/uru4000.c -@@ -1,6 +1,7 @@ - /* -- * Digital Persona U.are.U 4000/4000B driver for libfprint -+ * Digital Persona U.are.U 4000/4000B/4500 driver for libfprint - * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> -+ * Copyright (C) 2012 Timo Teräs <timo.teras@iki.fi> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -34,14 +35,14 @@ - #define USB_RQ 0x04 - #define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) - #define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) --#define CTRL_TIMEOUT 5000 --#define BULK_TIMEOUT 5000 --#define DATABLK_RQLEN 0x1b340 --#define DATABLK_EXPECT 0x1b1c0 --#define CAPTURE_HDRLEN 64 -+#define CTRL_TIMEOUT 5000 -+#define BULK_TIMEOUT 5000 - #define IRQ_LENGTH 64 - #define CR_LENGTH 16 - -+#define IMAGE_HEIGHT 290 -+#define IMAGE_WIDTH 384 -+ - enum { - IRQDATA_SCANPWR_ON = 0x56aa, - IRQDATA_FINGER_ON = 0x0101, -@@ -51,7 +52,10 @@ enum { - - enum { - REG_HWSTAT = 0x07, -+ REG_SCRAMBLE_DATA_INDEX = 0x33, -+ REG_SCRAMBLE_DATA_KEY = 0x34, - REG_MODE = 0x4e, -+ REG_DEVICE_INFO = 0xf0, - /* firmware starts at 0x100 */ - REG_RESPONSE = 0x2000, - REG_CHALLENGE = 0x2010, -@@ -62,7 +66,8 @@ enum { - MODE_AWAIT_FINGER_ON = 0x10, - MODE_AWAIT_FINGER_OFF = 0x12, - MODE_CAPTURE = 0x20, -- MODE_SHUT_UP = 0x30, -+ MODE_CAPTURE_AUX = 0x30, -+ MODE_OFF = 0x70, - MODE_READY = 0x80, - }; - -@@ -78,6 +83,7 @@ enum { - static const struct uru4k_dev_profile { - const char *name; - gboolean auth_cr; -+ gboolean encryption; - } uru4k_dev_info[] = { - [MS_KBD] = { - .name = "Microsoft Keyboard with Fingerprint Reader", -@@ -102,21 +108,10 @@ static const struct uru4k_dev_profile { - [DP_URU4000B] = { - .name = "Digital Persona U.are.U 4000B", - .auth_cr = FALSE, -+ .encryption = TRUE, - }, - }; - --/* As we don't know the encryption scheme, we have to disable encryption -- * by powering the device down and modifying the firmware. The location of -- * the encryption control byte changes based on device revision. -- * -- * We use a search approach to find it: we look at the 3 bytes of data starting -- * from these addresses, looking for a pattern "ff X7 41" (where X is dontcare) -- * When we find a pattern we know that the encryption byte ius the X7 byte. -- */ --static const uint16_t fwenc_offsets[] = { -- 0x510, 0x62d, 0x792, 0x7f4, --}; -- - typedef void (*irq_cb_fn)(struct fp_img_dev *dev, int status, uint16_t type, - void *user_data); - typedef void (*irqs_stopped_cb_fn)(struct fp_img_dev *dev); -@@ -125,11 +120,14 @@ struct uru4k_dev { - const struct uru4k_dev_profile *profile; - uint8_t interface; - enum fp_imgdev_state activate_state; -- unsigned char last_reg_rd; -+ unsigned char last_reg_rd[16]; - unsigned char last_hwstat; - - struct libusb_transfer *irq_transfer; - struct libusb_transfer *img_transfer; -+ void *img_data; -+ uint16_t img_lines_done, img_block; -+ uint32_t img_enc_seed; - - irq_cb_fn irq_cb; - void *irq_cb_data; -@@ -225,7 +223,7 @@ static int write_reg(struct fp_img_dev *dev, uint16_t reg, - } - - typedef void (*read_regs_cb_fn)(struct fp_img_dev *dev, int status, -- unsigned char *data, void *user_data); -+ uint16_t num_regs, unsigned char *data, void *user_data); - - struct read_regs_data { - struct fp_img_dev *dev; -@@ -248,7 +246,7 @@ static void read_regs_cb(struct libusb_transfer *transfer) - else - data = libusb_control_transfer_get_data(transfer); - -- rrdata->callback(rrdata->dev, r, data, rrdata->user_data); -+ rrdata->callback(rrdata->dev, r, transfer->actual_length, data, rrdata->user_data); - g_free(rrdata); - g_free(transfer->buffer); - libusb_free_transfer(transfer); -@@ -284,12 +282,6 @@ static int read_regs(struct fp_img_dev *dev, uint16_t first_reg, - return r; - } - --static int read_reg(struct fp_img_dev *dev, uint16_t reg, -- read_regs_cb_fn callback, void *user_data) --{ -- return read_regs(dev, reg, 1, callback, user_data); --} -- - /* - * HWSTAT - * -@@ -325,7 +317,7 @@ static void response_cb(struct fp_img_dev *dev, int status, void *user_data) - } - - static void challenge_cb(struct fp_img_dev *dev, int status, -- unsigned char *data, void *user_data) -+ uint16_t num_regs, unsigned char *data, void *user_data) - { - struct fpi_ssm *ssm = user_data; - struct uru4k_dev *urudev = dev->priv; -@@ -469,95 +461,10 @@ static void stop_irq_handler(struct fp_img_dev *dev, irqs_stopped_cb_fn cb) - } - } - --/***** IMAGING LOOP *****/ -- --static int start_imaging_loop(struct fp_img_dev *dev); -- --static void image_cb(struct libusb_transfer *transfer) --{ -- struct fp_img_dev *dev = transfer->user_data; -- struct uru4k_dev *urudev = dev->priv; -- int hdr_skip = CAPTURE_HDRLEN; -- int image_size = DATABLK_EXPECT - CAPTURE_HDRLEN; -- struct fp_img *img; -- int r = 0; -- -- /* remove the global reference early: otherwise we may report results, -- * leading to immediate deactivation of driver, which will potentially -- * try to cancel an already-completed transfer */ -- urudev->img_transfer = NULL; -- -- if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { -- fp_dbg("cancelled"); -- g_free(transfer->buffer); -- libusb_free_transfer(transfer); -- return; -- } else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { -- r = -EIO; -- goto out; -- } -- -- if (transfer->actual_length == image_size) { -- /* no header! this is rather odd, but it happens sometimes with my MS -- * keyboard */ -- fp_dbg("got image with no header!"); -- hdr_skip = 0; -- } else if (transfer->actual_length != DATABLK_EXPECT) { -- fp_err("unexpected image capture size (%d)", transfer->actual_length); -- r = -EPROTO; -- goto out; -- } -- -- img = fpi_img_new(image_size); -- memcpy(img->data, transfer->buffer + hdr_skip, image_size); -- img->flags = FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED | FP_IMG_COLORS_INVERTED; -- fpi_imgdev_image_captured(dev, img); -- --out: -- g_free(transfer->buffer); -- libusb_free_transfer(transfer); -- if (r == 0) -- r = start_imaging_loop(dev); -- -- if (r) -- fpi_imgdev_session_error(dev, r); --} -- --static int start_imaging_loop(struct fp_img_dev *dev) --{ -- struct uru4k_dev *urudev = dev->priv; -- struct libusb_transfer *transfer = libusb_alloc_transfer(0); -- unsigned char *data; -- int r; -- -- if (!transfer) -- return -ENOMEM; -- -- data = g_malloc(DATABLK_RQLEN); -- libusb_fill_bulk_transfer(transfer, dev->udev, EP_DATA, data, -- DATABLK_RQLEN, image_cb, dev, 0); -- -- urudev->img_transfer = transfer; -- r = libusb_submit_transfer(transfer); -- if (r < 0) { -- g_free(data); -- libusb_free_transfer(transfer); -- } -- -- return r; --} -- --static void stop_imaging_loop(struct fp_img_dev *dev) --{ -- struct uru4k_dev *urudev = dev->priv; -- struct libusb_transfer *transfer = urudev->img_transfer; -- if (transfer) -- libusb_cancel_transfer(transfer); -- /* FIXME: should probably wait for cancellation to complete */ --} -- - /***** STATE CHANGING *****/ - -+static int execute_state_change(struct fp_img_dev *dev); -+ - static void finger_presence_irq_cb(struct fp_img_dev *dev, int status, - uint16_t type, void *user_data) - { -@@ -582,33 +489,22 @@ static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state) - { - struct uru4k_dev *urudev = dev->priv; - -- stop_imaging_loop(dev); -- - switch (state) { -+ case IMGDEV_STATE_INACTIVE: - case IMGDEV_STATE_AWAIT_FINGER_ON: -- if (!IRQ_HANDLER_IS_RUNNING(urudev)) -- return -EIO; -- urudev->irq_cb = finger_presence_irq_cb; -- return write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_ON, -- change_state_write_reg_cb, NULL); -- -- case IMGDEV_STATE_CAPTURE: -- urudev->irq_cb = NULL; -- start_imaging_loop(dev); -- return write_reg(dev, REG_MODE, MODE_CAPTURE, change_state_write_reg_cb, -- NULL); -- - case IMGDEV_STATE_AWAIT_FINGER_OFF: -- if (!IRQ_HANDLER_IS_RUNNING(urudev)) -- return -EIO; -- urudev->irq_cb = finger_presence_irq_cb; -- return write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_OFF, -- change_state_write_reg_cb, NULL); -- -+ case IMGDEV_STATE_CAPTURE: -+ break; - default: - fp_err("unrecognised state %d", state); - return -EINVAL; - } -+ -+ urudev->activate_state = state; -+ if (urudev->img_transfer != NULL) -+ return 0; -+ -+ return execute_state_change(dev); - } - - /***** GENERIC STATE MACHINE HELPER FUNCTIONS *****/ -@@ -623,17 +519,23 @@ static void sm_write_reg_cb(struct fp_img_dev *dev, int result, void *user_data) - fpi_ssm_next_state(ssm); - } - --static void sm_write_reg(struct fpi_ssm *ssm, uint16_t reg, -- unsigned char value) -+static void sm_write_regs(struct fpi_ssm *ssm, uint16_t first_reg, uint16_t num_regs, -+ void *data) - { - struct fp_img_dev *dev = ssm->priv; -- int r = write_reg(dev, reg, value, sm_write_reg_cb, ssm); -+ int r = write_regs(dev, first_reg, num_regs, data, sm_write_reg_cb, ssm); - if (r < 0) - fpi_ssm_mark_aborted(ssm, r); - } - -+static void sm_write_reg(struct fpi_ssm *ssm, uint16_t reg, -+ unsigned char value) -+{ -+ sm_write_regs(ssm, reg, 1, &value); -+} -+ - static void sm_read_reg_cb(struct fp_img_dev *dev, int result, -- unsigned char *data, void *user_data) -+ uint16_t num_regs, unsigned char *data, void *user_data) - { - struct fpi_ssm *ssm = user_data; - struct uru4k_dev *urudev = dev->priv; -@@ -641,27 +543,32 @@ static void sm_read_reg_cb(struct fp_img_dev *dev, int result, - if (result) { - fpi_ssm_mark_aborted(ssm, result); - } else { -- urudev->last_reg_rd = *data; -- fp_dbg("reg value %x", urudev->last_reg_rd); -+ memcpy(urudev->last_reg_rd, data, num_regs); -+ fp_dbg("reg value %x", urudev->last_reg_rd[0]); - fpi_ssm_next_state(ssm); - } - } - --static void sm_read_reg(struct fpi_ssm *ssm, uint16_t reg) -+static void sm_read_regs(struct fpi_ssm *ssm, uint16_t reg, uint16_t num_regs) - { - struct fp_img_dev *dev = ssm->priv; -+ struct uru4k_dev *urudev = dev->priv; - int r; -- -- fp_dbg("read reg %x", reg); -- r = read_reg(dev, reg, sm_read_reg_cb, ssm); -+ -+ if (num_regs > sizeof(urudev->last_reg_rd)) { -+ fpi_ssm_mark_aborted(ssm, -EIO); -+ return; -+ } -+ -+ fp_dbg("read %d regs at %x", num_regs, reg); -+ r = read_regs(dev, reg, num_regs, sm_read_reg_cb, ssm); - if (r < 0) - fpi_ssm_mark_aborted(ssm, r); - } - --static void sm_set_mode(struct fpi_ssm *ssm, unsigned char mode) -+static void sm_read_reg(struct fpi_ssm *ssm, uint16_t reg) - { -- fp_dbg("mode %02x", mode); -- sm_write_reg(ssm, REG_MODE, mode); -+ sm_read_regs(ssm, reg, 1); - } - - static void sm_set_hwstat(struct fpi_ssm *ssm, unsigned char value) -@@ -670,77 +577,232 @@ static void sm_set_hwstat(struct fpi_ssm *ssm, unsigned char value) - sm_write_reg(ssm, REG_HWSTAT, value); - } - --/***** INITIALIZATION *****/ -+/***** IMAGING LOOP *****/ - --enum fwfixer_states { -- FWFIXER_INIT, -- FWFIXER_READ_NEXT, -- FWFIXER_WRITE, -- FWFIXER_NUM_STATES, -+enum imaging_states { -+ IMAGING_CAPTURE, -+ IMAGING_SEND_INDEX, -+ IMAGING_READ_KEY, -+ IMAGING_DECODE, -+ IMAGING_REPORT_IMAGE, -+ IMAGING_NUM_STATES - }; - --static void fwfixer_read_cb(struct fp_img_dev *dev, int status, -- unsigned char *data, void *user_data) -+static void image_transfer_cb(struct libusb_transfer *transfer) - { -- struct fpi_ssm *ssm = user_data; -- struct uru4k_dev *urudev = dev->priv; -- -- if (status != 0) -- fpi_ssm_mark_aborted(ssm, status); -+ struct fpi_ssm *ssm = transfer->user_data; - -- fp_dbg("data: %02x %02x %02x", data[0], data[1], data[2]); -- if (data[0] == 0xff && (data[1] & 0x0f) == 0x07 && data[2] == 0x41) { -- fp_dbg("using offset %x", fwenc_offsets[urudev->fwfixer_offset]); -- urudev->fwfixer_value = data[1]; -- fpi_ssm_jump_to_state(ssm, FWFIXER_WRITE); -+ if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { -+ fp_dbg("cancelled"); -+ fpi_ssm_mark_aborted(ssm, -ECANCELED); -+ } else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { -+ fp_dbg("error"); -+ fpi_ssm_mark_aborted(ssm, -EIO); - } else { -- fpi_ssm_jump_to_state(ssm, FWFIXER_READ_NEXT); -+ fpi_ssm_next_state(ssm); -+ } -+} -+ -+enum { -+ BLOCKF_CHANGE_KEY = 0x80, -+ BLOCKF_NO_KEY_UPDATE = 0x04, -+ BLOCKF_ENCRYPTED = 0x02, -+ BLOCKF_NOT_PRESENT = 0x01, -+}; -+ -+struct uru4k_image { -+ uint8_t unknown_00[4]; -+ uint16_t num_lines; -+ uint8_t key_number; -+ uint8_t unknown_07[9]; -+ struct { -+ uint8_t flags; -+ uint8_t num_lines; -+ } block_info[15]; -+ uint8_t unknown_2E[18]; -+ uint8_t data[IMAGE_HEIGHT][IMAGE_WIDTH]; -+}; -+ -+static uint32_t update_key(uint32_t key) -+{ -+ /* linear feedback shift register -+ * taps at bit positions 1 3 4 7 11 13 20 23 26 29 32 */ -+ uint32_t bit = key & 0x9248144d; -+ bit ^= bit << 16; -+ bit ^= bit << 8; -+ bit ^= bit << 4; -+ bit ^= bit << 2; -+ bit ^= bit << 1; -+ return (bit & 0x80000000) | (key >> 1); -+} -+ -+static uint32_t do_decode(uint8_t *data, int num_bytes, uint32_t key) -+{ -+ uint8_t xorbyte; -+ int i; -+ -+ for (i = 0; i < num_bytes - 1; i++) { -+ /* calculate xor byte and update key */ -+ xorbyte = ((key >> 4) & 1) << 0; -+ xorbyte |= ((key >> 8) & 1) << 1; -+ xorbyte |= ((key >> 11) & 1) << 2; -+ xorbyte |= ((key >> 14) & 1) << 3; -+ xorbyte |= ((key >> 18) & 1) << 4; -+ xorbyte |= ((key >> 21) & 1) << 5; -+ xorbyte |= ((key >> 24) & 1) << 6; -+ xorbyte |= ((key >> 29) & 1) << 7; -+ key = update_key(key); -+ -+ /* decrypt data */ -+ data[i] = data[i+1] ^ xorbyte; - } -+ -+ /* the final byte is implictly zero */ -+ data[i] = 0; -+ return update_key(key); - } - --static void fwfixer_run_state(struct fpi_ssm *ssm) -+static void imaging_run_state(struct fpi_ssm *ssm) - { - struct fp_img_dev *dev = ssm->priv; - struct uru4k_dev *urudev = dev->priv; -- int r; -+ struct uru4k_image *img = urudev->img_data; -+ struct fp_img *fpimg; -+ uint32_t key; -+ uint8_t flags, num_lines; -+ int i, r, to; -+ char buf[5]; - - switch (ssm->cur_state) { -- case FWFIXER_INIT: -- urudev->fwfixer_offset = -1; -- fpi_ssm_next_state(ssm); -+ case IMAGING_CAPTURE: -+ urudev->img_lines_done = 0; -+ urudev->img_block = 0; -+ libusb_fill_bulk_transfer(urudev->img_transfer, dev->udev, EP_DATA, -+ urudev->img_data, sizeof(struct uru4k_image), image_transfer_cb, ssm, 0); -+ r = libusb_submit_transfer(urudev->img_transfer); -+ if (r < 0) -+ fpi_ssm_mark_aborted(ssm, -EIO); - break; -- case FWFIXER_READ_NEXT: ; -- int offset = ++urudev->fwfixer_offset; -- uint16_t try_addr; -- -- if (offset == G_N_ELEMENTS(fwenc_offsets)) { -- fp_err("could not find encryption byte"); -- fpi_ssm_mark_aborted(ssm, -ENODEV); -+ case IMAGING_SEND_INDEX: -+ fp_dbg("hw header lines %d", img->num_lines); -+ -+ if (img->num_lines >= IMAGE_HEIGHT || -+ urudev->img_transfer->actual_length != img->num_lines * IMAGE_WIDTH + 64) { -+ fp_err("bad captured image (%d lines) or size mismatch %d != %d", -+ img->num_lines, -+ urudev->img_transfer->actual_length, -+ img->num_lines * IMAGE_WIDTH + 64); -+ fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE); - return; - } -- -- try_addr = fwenc_offsets[offset]; -- fp_dbg("looking for encryption byte at %x", try_addr); -- -- r = read_regs(dev, try_addr, 3, fwfixer_read_cb, ssm); -- if (r < 0) -- fpi_ssm_mark_aborted(ssm, r); -+ if (!urudev->profile->encryption) { -+ fpi_ssm_jump_to_state(ssm, IMAGING_REPORT_IMAGE); -+ return; -+ } -+ buf[0] = img->key_number; -+ buf[1] = urudev->img_enc_seed; -+ buf[2] = urudev->img_enc_seed >> 8; -+ buf[3] = urudev->img_enc_seed >> 16; -+ buf[4] = urudev->img_enc_seed >> 24; -+ sm_write_regs(ssm, REG_SCRAMBLE_DATA_INDEX, 5, buf); - break; -- case FWFIXER_WRITE: ; -- uint16_t enc_addr = fwenc_offsets[urudev->fwfixer_offset] + 1; -- unsigned char cur = urudev->fwfixer_value; -- unsigned char new = cur & 0xef; -- if (new == cur) { -- fp_dbg("encryption is already disabled"); -- fpi_ssm_next_state(ssm); -- } else { -- fp_dbg("fixing encryption byte at %x to %02x", enc_addr, new); -- sm_write_reg(ssm, enc_addr, new); -+ case IMAGING_READ_KEY: -+ sm_read_regs(ssm, REG_SCRAMBLE_DATA_KEY, 4); -+ break; -+ case IMAGING_DECODE: -+ key = urudev->last_reg_rd[0]; -+ key |= urudev->last_reg_rd[1] << 8; -+ key |= urudev->last_reg_rd[2] << 16; -+ key |= urudev->last_reg_rd[3] << 24; -+ key ^= urudev->img_enc_seed; -+ -+ fp_dbg("encryption id %02x -> key %08x", img->key_number, key); -+ while (urudev->img_block < array_n_elements(img->block_info) && -+ urudev->img_lines_done < img->num_lines) { -+ flags = img->block_info[urudev->img_block].flags; -+ num_lines = img->block_info[urudev->img_block].num_lines; -+ if (num_lines == 0) -+ break; -+ -+ fp_dbg("%d %02x %d", urudev->img_block, flags, num_lines); -+ if (flags & BLOCKF_CHANGE_KEY) { -+ fp_dbg("changing encryption keys.\n"); -+ img->block_info[urudev->img_block].flags &= ~BLOCKF_CHANGE_KEY; -+ img->key_number++; -+ urudev->img_enc_seed = rand(); -+ fpi_ssm_jump_to_state(ssm, IMAGING_SEND_INDEX); -+ return; -+ } -+ switch (flags & (BLOCKF_NO_KEY_UPDATE | BLOCKF_ENCRYPTED)) { -+ case BLOCKF_ENCRYPTED: -+ fp_dbg("decoding %d lines", num_lines); -+ key = do_decode(&img->data[urudev->img_lines_done][0], -+ IMAGE_WIDTH*num_lines, key); -+ break; -+ case 0: -+ fp_dbg("skipping %d lines", num_lines); -+ for (r = 0; r < IMAGE_WIDTH*num_lines; r++) -+ key = update_key(key); -+ break; -+ } -+ if ((flags & BLOCKF_NOT_PRESENT) == 0) -+ urudev->img_lines_done += num_lines; -+ urudev->img_block++; -+ } -+ fpi_ssm_next_state(ssm); -+ break; -+ case IMAGING_REPORT_IMAGE: -+ fpimg = fpi_img_new_for_imgdev(dev); -+ -+ to = r = 0; -+ for (i = 0; i < array_n_elements(img->block_info) && r < img->num_lines; i++) { -+ flags = img->block_info[i].flags; -+ num_lines = img->block_info[i].num_lines; -+ if (num_lines == 0) -+ break; -+ memcpy(&fpimg->data[to], &img->data[r][0], -+ num_lines * IMAGE_WIDTH); -+ if (!(flags & BLOCKF_NOT_PRESENT)) -+ r += num_lines; -+ to += num_lines * IMAGE_WIDTH; - } -+ -+ fpimg->flags = FP_IMG_COLORS_INVERTED; -+ if (!urudev->profile->encryption) -+ fpimg->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED; -+ fpi_imgdev_image_captured(dev, fpimg); -+ -+ if (urudev->activate_state == IMGDEV_STATE_CAPTURE) -+ fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE); -+ else -+ fpi_ssm_mark_completed(ssm); - break; - } - } - -+static void imaging_complete(struct fpi_ssm *ssm) -+{ -+ struct fp_img_dev *dev = ssm->priv; -+ struct uru4k_dev *urudev = dev->priv; -+ int r = ssm->error; -+ fpi_ssm_free(ssm); -+ -+ g_free(urudev->img_data); -+ urudev->img_data = NULL; -+ -+ libusb_free_transfer(urudev->img_transfer); -+ urudev->img_transfer = NULL; -+ -+ if (r) -+ fpi_imgdev_session_error(dev, r); -+ -+ r = execute_state_change(dev); -+ if (r) -+ fpi_imgdev_session_error(dev, r); -+} -+ -+/***** INITIALIZATION *****/ -+ - /* After closing an app and setting hwstat to 0x80, my ms keyboard gets in a - * confused state and returns hwstat 0x85. On next app run, we don't get the - * 56aa interrupt. This is the best way I've found to fix it: mess around -@@ -793,7 +855,7 @@ static void rebootpwr_run_state(struct fpi_ssm *ssm) - sm_read_reg(ssm, REG_HWSTAT); - break; - case REBOOTPWR_CHECK_HWSTAT: -- urudev->last_hwstat = urudev->last_reg_rd; -+ urudev->last_hwstat = urudev->last_reg_rd[0]; - if (urudev->last_hwstat & 0x1) - fpi_ssm_mark_completed(ssm); - else -@@ -876,8 +938,8 @@ static void powerup_run_state(struct fpi_ssm *ssm) - sm_read_reg(ssm, REG_HWSTAT); - break; - case POWERUP_CHECK_HWSTAT: -- urudev->last_hwstat = urudev->last_reg_rd; -- if ((urudev->last_reg_rd & 0x80) == 0) -+ urudev->last_hwstat = urudev->last_reg_rd[0]; -+ if ((urudev->last_reg_rd[0] & 0x80) == 0) - fpi_ssm_mark_completed(ssm); - else - fpi_ssm_next_state(ssm); -@@ -890,7 +952,7 @@ static void powerup_run_state(struct fpi_ssm *ssm) - sm_do_challenge_response(ssm); - break; - case POWERUP_CHALLENGE_RESPONSE_SUCCESS: -- fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT); -+ fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT); - break; - } - } -@@ -908,12 +970,6 @@ static void powerup_run_state(struct fpi_ssm *ssm) - if ((status & 0x80) == 0) - set_hwstat(status | 0x80); - -- // disable encryption -- fwenc = read_firmware_encryption_byte(); -- new = fwenc & 0xef; -- if (new != fwenc) -- write_firmware_encryption_byte(new); -- - // power device up - run_powerup_sm(); - await_irq(IRQDATA_SCANPWR_ON); -@@ -924,10 +980,11 @@ enum init_states { - INIT_CHECK_HWSTAT_REBOOT, - INIT_REBOOT_POWER, - INIT_CHECK_HWSTAT_POWERDOWN, -- INIT_FIX_FIRMWARE, - INIT_POWERUP, - INIT_AWAIT_SCAN_POWER, - INIT_DONE, -+ INIT_GET_VERSION, -+ INIT_REPORT_VERSION, - INIT_NUM_STATES, - }; - -@@ -975,7 +1032,7 @@ static void init_run_state(struct fpi_ssm *ssm) - sm_read_reg(ssm, REG_HWSTAT); - break; - case INIT_CHECK_HWSTAT_REBOOT: -- urudev->last_hwstat = urudev->last_reg_rd; -+ urudev->last_hwstat = urudev->last_reg_rd[0]; - if ((urudev->last_hwstat & 0x84) == 0x84) - fpi_ssm_next_state(ssm); - else -@@ -993,12 +1050,6 @@ static void init_run_state(struct fpi_ssm *ssm) - else - fpi_ssm_next_state(ssm); - break; -- case INIT_FIX_FIRMWARE: ; -- struct fpi_ssm *fwsm = fpi_ssm_new(dev->dev, fwfixer_run_state, -- FWFIXER_NUM_STATES); -- fwsm->priv = dev; -- fpi_ssm_start_subsm(ssm, fwsm); -- break; - case INIT_POWERUP: ; - struct fpi_ssm *powerupsm = fpi_ssm_new(dev->dev, powerup_run_state, - POWERUP_NUM_STATES); -@@ -1029,6 +1080,17 @@ static void init_run_state(struct fpi_ssm *ssm) - urudev->scanpwr_irq_timeout = NULL; - urudev->irq_cb_data = NULL; - urudev->irq_cb = NULL; -+ fpi_ssm_next_state(ssm); -+ break; -+ case INIT_GET_VERSION: -+ sm_read_regs(ssm, REG_DEVICE_INFO, 16); -+ break; -+ case INIT_REPORT_VERSION: -+ /* Likely hardware revision, and firmware version. -+ * Not sure which is which. */ -+ fp_info("Versions %02x%02x and %02x%02x", -+ urudev->last_reg_rd[10], urudev->last_reg_rd[11], -+ urudev->last_reg_rd[4], urudev->last_reg_rd[5]); - fpi_ssm_mark_completed(ssm); - break; - } -@@ -1037,7 +1099,6 @@ static void init_run_state(struct fpi_ssm *ssm) - static void activate_initsm_complete(struct fpi_ssm *ssm) - { - struct fp_img_dev *dev = ssm->priv; -- struct uru4k_dev *urudev = dev->priv; - int r = ssm->error; - fpi_ssm_free(ssm); - -@@ -1046,7 +1107,7 @@ static void activate_initsm_complete(struct fpi_ssm *ssm) - return; - } - -- r = dev_change_state(dev, urudev->activate_state); -+ r = execute_state_change(dev); - fpi_imgdev_activate_complete(dev, r); - } - -@@ -1074,47 +1135,69 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state) - - /***** DEINITIALIZATION *****/ - --enum deinit_states { -- DEINIT_SET_MODE_INIT = 0, -- DEINIT_POWERDOWN, -- DEINIT_NUM_STATES, --}; -- --static void deinit_run_state(struct fpi_ssm *ssm) --{ -- switch (ssm->cur_state) { -- case DEINIT_SET_MODE_INIT: -- sm_set_mode(ssm, MODE_INIT); -- break; -- case DEINIT_POWERDOWN: -- sm_set_hwstat(ssm, 0x80); -- break; -- } --} -- - static void deactivate_irqs_stopped(struct fp_img_dev *dev) - { - fpi_imgdev_deactivate_complete(dev); - } - --static void deactivate_deinitsm_complete(struct fpi_ssm *ssm) -+static void deactivate_write_reg_cb(struct fp_img_dev *dev, int status, -+ void *user_data) - { -- struct fp_img_dev *dev = ssm->priv; -- fpi_ssm_free(ssm); - stop_irq_handler(dev, deactivate_irqs_stopped); - } - - static void dev_deactivate(struct fp_img_dev *dev) - { -+ dev_change_state(dev, IMGDEV_STATE_INACTIVE); -+} -+ -+static int execute_state_change(struct fp_img_dev *dev) -+{ - struct uru4k_dev *urudev = dev->priv; -- struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, deinit_run_state, -- DEINIT_NUM_STATES); -+ struct fpi_ssm *ssm; - -- stop_imaging_loop(dev); -- urudev->irq_cb = NULL; -- urudev->irq_cb_data = NULL; -- ssm->priv = dev; -- fpi_ssm_start(ssm, deactivate_deinitsm_complete); -+ switch (urudev->activate_state) { -+ case IMGDEV_STATE_INACTIVE: -+ fp_dbg("deactivating"); -+ urudev->irq_cb = NULL; -+ urudev->irq_cb_data = NULL; -+ return write_reg(dev, REG_MODE, MODE_OFF, -+ deactivate_write_reg_cb, NULL); -+ break; -+ -+ case IMGDEV_STATE_AWAIT_FINGER_ON: -+ fp_dbg("wait finger on"); -+ if (!IRQ_HANDLER_IS_RUNNING(urudev)) -+ return -EIO; -+ urudev->irq_cb = finger_presence_irq_cb; -+ return write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_ON, -+ change_state_write_reg_cb, NULL); -+ -+ case IMGDEV_STATE_CAPTURE: -+ fp_dbg("starting capture"); -+ urudev->irq_cb = NULL; -+ -+ urudev->img_transfer = libusb_alloc_transfer(0); -+ urudev->img_data = g_malloc(sizeof(struct uru4k_image)); -+ urudev->img_enc_seed = rand(); -+ -+ ssm = fpi_ssm_new(dev->dev, imaging_run_state, IMAGING_NUM_STATES); -+ ssm->priv = dev; -+ fpi_ssm_start(ssm, imaging_complete); -+ -+ return write_reg(dev, REG_MODE, MODE_CAPTURE, -+ change_state_write_reg_cb, NULL); -+ -+ case IMGDEV_STATE_AWAIT_FINGER_OFF: -+ fp_dbg("await finger off"); -+ if (!IRQ_HANDLER_IS_RUNNING(urudev)) -+ return -EIO; -+ urudev->irq_cb = finger_presence_irq_cb; -+ return write_reg(dev, REG_MODE, MODE_AWAIT_FINGER_OFF, -+ change_state_write_reg_cb, NULL); -+ } -+ -+ return 0; - } - - /***** LIBRARY STUFF *****/ -@@ -1278,13 +1361,13 @@ struct fp_img_driver uru4000_driver = { - .driver = { - .id = 2, - .name = FP_COMPONENT, -- .full_name = "Digital Persona U.are.U 4000/4000B", -+ .full_name = "Digital Persona U.are.U 4000/4000B/4500", - .id_table = id_table, - .scan_type = FP_SCAN_TYPE_PRESS, - }, - .flags = FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE, -- .img_height = 289, -- .img_width = 384, -+ .img_height = IMAGE_HEIGHT, -+ .img_width = IMAGE_WIDTH, - - .open = dev_init, - .close = dev_deinit, -diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h -index 44881cd..8e714ec 100644 ---- a/libfprint/fp_internal.h -+++ b/libfprint/fp_internal.h -@@ -28,6 +28,8 @@ - - #include <fprint.h> - -+#define array_n_elements(array) (sizeof(array) / sizeof(array[0])) -+ - #define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) --- -1.7.12 - |