rpms/libfprint/F-12 aes1610.c, NONE, 1.1 libfprint-aes1610-driver.patch, NONE, 1.1 libfprint.spec, 1.26, 1.27

Bastien Nocera hadess at fedoraproject.org
Mon Nov 30 11:07:29 UTC 2009


Author: hadess

Update of /cvs/pkgs/rpms/libfprint/F-12
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv21781

Modified Files:
	libfprint.spec 
Added Files:
	aes1610.c libfprint-aes1610-driver.patch 
Log Message:
* Mon Nov 30 2009 Bastien Nocera <bnocera at redhat.com> 0.1.0-13.pre2
- Add aes1610 driver (#499732)



--- NEW FILE aes1610.c ---
/*
 * AuthenTec AES1610 driver for libfprint
 * Copyright (C) 2007 Anthony Bretaudeau <wxcover at users.sourceforge.net>
 * Copyright (C) 2007 Daniel Drake <dsd at gentoo.org>
 * Copyright (C) 2007 Cyrille Bagard
 * Copyright (C) 2007 Vasily Khoruzhick
 *
 * Based on code from http://home.gna.org/aes2501, relicensed with permission
 *
 * 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 "aes1610"

#include <errno.h>
#include <string.h>

#include <libusb.h>

#include <aeslib.h>
#include <fp_internal.h>

/* 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
 * computer.
 * Unless the user is scanning their finger unreasonably fast, the frames
 * *will* overlap. The implementation below detects this overlap and produces
 * a contiguous image as the end result.
 * The fact that the user determines the length of the swipe (and hence the
 * number of useful frames) and also the fact that overlap varies means that
 * images returned from this driver vary in height.
 */

#define FRAME_WIDTH		128
#define FRAME_HEIGHT	8
#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)
{
	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 }
};

static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
	int r;

	r = libusb_claim_interface(dev->udev, 0);
	if (r < 0) {
		fp_err("could not claim interface 0");
		return r;
	}

	/* FIXME check endpoints */

	return aes_write_regv(dev, init, G_N_ELEMENTS(init));
}

static int do_exit(struct fp_img_dev *dev)
{
	return aes_write_regv(dev, stop_reader, G_N_ELEMENTS(stop_reader));
}

static void dev_exit(struct fp_img_dev *dev)
{
	do_exit(dev);
	libusb_release_interface(dev->udev, 0);
}

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)
{
	unsigned char buffer[19];
	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;

	r = read_data(dev, buffer, 19);
	if (r < 0)
		return r;

	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;
	}
	
	return sum > 20;
}

static int await_finger_on(struct fp_img_dev *dev)
{
	int r;
	do {
		r = detect_finger(dev);
	} while (r == 0);
	return (r < 0) ? r : 0;
}

/* find overlapping parts of frames */
static unsigned int find_overlap(unsigned char *first_frame,
	unsigned char *second_frame, unsigned int *min_error)
{
	unsigned int dy;
	unsigned int not_overlapped_height = 0;
	*min_error = 255 * FRAME_SIZE;
	for (dy = 0; dy < FRAME_HEIGHT; dy++) {
		/* Calculating difference (error) between parts of frames */
		unsigned int i;
		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]); 
		}
		
		/* Normalize error */
		error *= 15;
		error /= i;
		if (error < *min_error) {
			*min_error = error;
			not_overlapped_height = dy;
		}
		first_frame += FRAME_WIDTH;
	}
	
	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)
{
	uint8_t *assembled = output;
	int frame;
	uint32_t image_height = FRAME_HEIGHT;
	unsigned int min_error;
	*errors_sum = 0;

	if (num_strips < 1)
		return 0;
	
	/* 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);

		if (reverse)
			output -= FRAME_SIZE;
		else
			output += FRAME_SIZE;
	}

	/* Detecting where frames overlaped */
	output = assembled;
	for (frame = 1; frame < num_strips; frame++) {
		int not_overlapped;

		output += FRAME_SIZE;
		not_overlapped = find_overlap(assembled, output, &min_error);
		*errors_sum += min_error;
		image_height += not_overlapped;
		assembled += FRAME_WIDTH * not_overlapped;
		memcpy(assembled, output, FRAME_SIZE); 
	}
	return image_height;
}

static const struct aes_regwrite capture_reqs[] = {
	{ 0x80, 0x01 },
	{ 0x80, 0x12 },
	{ 0x84, 0x01 },
	{ 0x85, 0x00 },
	{ 0x89, 0x64 },
	{ 0x8A, 0x00 },
	{ 0x8B, 0x0E },
	{ 0x8C, 0x90 },
	{ 0xBE, 0x23 },
	{ 0x29, 0x06 },
	{ 0x2A, 0x35 },
	{ 0x96, 0x00 },
	{ 0x98, 0x03 },
	{ 0x99, 0x00 },
	{ 0x9C, 0xA5 },
	{ 0x9D, 0x40 },
	{ 0x9E, 0xC6 },
	{ 0x9F, 0x8E },
	{ 0xA2, 0x50 },
	{ 0xA3, 0xF0 },
	{ 0xAD, 0x08 },
	{ 0xBD, 0x4F },
	{ 0xAF, 0x54 },
	{ 0xB1, 0x08 },
	{ 0xB5, 0xAB },
	{ 0x1B, 0x2D },
	{ 0xB6, 0x4E },
	{ 0xB8, 0x70 },
	{ 0x2B, 0xB3 },
	{ 0x2C, 0x5D },
	{ 0x2D, 0x98 },
	{ 0x2E, 0xB0 },
	{ 0x2F, 0x20 },
	{ 0xA2, 0xD0 },
	{ 0x1D, 0x21 },
	{ 0x1E, 0xBE },
	{ 0x1C, 0x00 },
	{ 0x1D, 0x30 },
	{ 0x1E, 0x29 },
	{ 0x1C, 0x01 },
	{ 0x1D, 0x00 },
	{ 0x1E, 0x9E },
	{ 0x1C, 0x02 },
	{ 0x1D, 0x30 },
	{ 0x1E, 0xBB },
	{ 0x1C, 0x03 },
	{ 0x1D, 0x00 },
	{ 0x1E, 0x9D },
	{ 0x1C, 0x04 },
	{ 0x1D, 0x22 },
	{ 0x1E, 0xFF },
	{ 0x1C, 0x05 },
	{ 0x1D, 0x1B },
	{ 0x1E, 0x4E },
	{ 0x1C, 0x06 },
	{ 0x1D, 0x16 },
	{ 0x1E, 0x28 },
	{ 0x1C, 0x07 },
	{ 0x1D, 0x22 },
	{ 0x1E, 0xFF },
	{ 0x1C, 0x08 },
	{ 0x1D, 0x15 },
	{ 0x1E, 0xF1 },
	{ 0x1C, 0x09 },
	{ 0x1D, 0x30 },
	{ 0x1E, 0xD5 },
	{ 0x1C, 0x0A },
	{ 0x1D, 0x00 },
	{ 0x1E, 0x9E },
	{ 0x1C, 0x0B },
	{ 0x1D, 0x17 },
	{ 0x1E, 0x9D },
	{ 0x1C, 0x0C },
	{ 0x1D, 0x28 },
	{ 0x1E, 0xD7 },
	{ 0x1C, 0x0D },
	{ 0x1D, 0x17 },
	{ 0x1E, 0xD7 },
	{ 0x1C, 0x0E },
	{ 0x1D, 0x0A },
	{ 0x1E, 0xCB },
	{ 0x1C, 0x0F },
	{ 0x1D, 0x24 },
	{ 0x1E, 0x14 },
	{ 0x1C, 0x10 },
	{ 0x1D, 0x17 },
	{ 0x1E, 0x85 },
	{ 0x1C, 0x11 },
	{ 0x1D, 0x15 },
	{ 0x1E, 0x71 },
	{ 0x1C, 0x12 },
	{ 0x1D, 0x2B },
	{ 0x1E, 0x36 },
	{ 0x1C, 0x13 },
	{ 0x1D, 0x12 },
	{ 0x1E, 0x06 },
	{ 0x1C, 0x14 },
	{ 0x1D, 0x30 },
	{ 0x1E, 0x97 },
	{ 0x1C, 0x15 },
	{ 0x1D, 0x21 },
	{ 0x1E, 0x32 },
	{ 0x1C, 0x16 },
	{ 0x1D, 0x06 },
	{ 0x1E, 0xE6 },
	{ 0x1C, 0x17 },
	{ 0x1D, 0x16 },
	{ 0x1E, 0x06 },
	{ 0x1C, 0x18 },
	{ 0x1D, 0x30 },
	{ 0x1E, 0x01 },
	{ 0x1C, 0x19 },
	{ 0x1D, 0x21 },
	{ 0x1E, 0x37 },
	{ 0x1C, 0x1A },
	{ 0x1D, 0x00 },
	{ 0x1E, 0x08 },
	{ 0x1C, 0x1B },
	{ 0x1D, 0x80 },
	{ 0x1E, 0xD5 },
	{ 0xA2, 0x50 },
	{ 0xA2, 0x50 },
	{ 0x81, 0x01 }
};

static const struct aes_regwrite strip_scan_reqs[] = {
	{ 0xBE, 0x23 },
	{ 0x29, 0x06 },
	{ 0x2A, 0x35 },
	{ 0xBD, 0x4F },
	{ 0xFF, 0x00 }
};

static const struct aes_regwrite capture_stop[] = {
	{ 0x81,0x00 }
};

static int capture(struct fp_img_dev *dev, gboolean unconditional,
	struct fp_img **ret)
{
	int r;
	struct fp_img *img;
	unsigned int nstrips;
	unsigned int errors_sum, r_errors_sum;
	unsigned char *cooked;
	unsigned char *imgptr;
	unsigned char buf[665];
	int final_size;
	int sum;
	unsigned int count_blank = 0;
	int i;

	/* FIXME can do better here in terms of buffer management? */
	fp_dbg("");

	r = aes_write_regv(dev, capture_reqs, G_N_ELEMENTS(capture_reqs));
	if (r < 0)
		return r;
  
	/* FIXME: use histogram data above for gain calibration (0x8e xx) */

	img = fpi_img_new((3 * MAX_FRAMES * FRAME_SIZE) / 2);
	imgptr = img->data;
	cooked = imgptr + (MAX_FRAMES * FRAME_SIZE) / 2;

	r = read_data(dev, buf, 665);
	if (r < 0)
		goto err;
	memcpy(imgptr, buf + 1, 128*4);
	imgptr += 128*4;

	r = read_data(dev, buf, 665);
	if (r < 0)
		goto err;
	memcpy(imgptr, buf + 1, 128*4);
	imgptr += 128*4;

	/* we start at 2 because we captured 2 frames above. the above captures
	 * should possibly be moved into the loop below, or discarded altogether */
	for (nstrips = 2; nstrips < MAX_FRAMES - 2; nstrips++) {
		r = aes_write_regv(dev, strip_scan_reqs, G_N_ELEMENTS(strip_scan_reqs));
		if (r < 0)
			goto err;
		r = read_data(dev, buf, 665);
		if (r < 0)
			goto err;
		memcpy(imgptr, buf + 1, 128*4);
		imgptr += 128*4;

		r = read_data(dev, buf, 665);
		if (r < 0)
			goto err;
		memcpy(imgptr, buf + 1, 128*4);
		imgptr += 128*4;

		sum = 0;
		for (i = 515; i != 530; i++)
		{
			/* histogram[i] = number of pixels of value i
			   Only the pixel values from 10 to 15 are used to detect finger. */
			sum += buf[i];
		}
		if (sum < 0) {
			r = sum;
			goto err;
		}
		fp_dbg("sum=%d", sum);
		if (sum == 0)
			count_blank++;
		else
			count_blank = 0;
			
		/* if we got 50 blank frames, assume scan has ended. */
		if (count_blank >= 50)
			break;
	}
	
	r = aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop));
	if (r < 0)
		goto err;
	r = read_data(dev, buf, 665);
	if (r < 0)
		goto err;
	memcpy(imgptr, buf + 1, 128*4);
	imgptr += 128*4;
	nstrips++;

	r = read_data(dev, buf, 665);
	if (r < 0)
		goto err;
	memcpy(imgptr, buf + 1, 128*4);
	imgptr += 128*4;
	nstrips++;
	
	if (nstrips == MAX_FRAMES)
		fp_warn("swiping finger too slow?");

	img->flags = FP_IMG_COLORS_INVERTED;
	img->height = assemble(img->data, cooked, nstrips, FALSE, &errors_sum);
	img->height = assemble(img->data, cooked, nstrips, TRUE, &r_errors_sum);
	
	if (r_errors_sum > errors_sum) {
		img->height = assemble(img->data, cooked, nstrips, FALSE, &errors_sum);
		img->flags |= FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
		fp_dbg("normal scan direction");
	} else {
		fp_dbg("reversed scan direction");
	}

	final_size = img->height * FRAME_WIDTH;
	memcpy(img->data, cooked, final_size);
	img = fpi_img_resize(img, final_size);
	*ret = img;
	return 0;
err:
	fp_img_free(img);
	return r;
}

static const struct usb_id id_table[] = {
	{ .vendor = 0x08ff, .product = 0x1600 },
	{ 0, 0, 0, },
};

struct fp_img_driver aes1610_driver = {
	.driver = {
		.id = 6,
		.name = FP_COMPONENT,
		.full_name = "AuthenTec AES1610",
		.id_table = id_table,
		.scan_type = FP_SCAN_TYPE_SWIPE,
	},
	.flags = 0,
	.img_height = -1,
	.img_width = 128,

	/* temporarily lowered until we sort out image processing code
	 * binarized scan quality is good, minutiae detection is accurate,
	 * it's just that we get fewer minutiae than other scanners (less scanning
	 * area) */
	.bz3_threshold = 10,

	.init = dev_init,
	.exit = dev_exit,
	.await_finger_on = await_finger_on,
	.capture = capture,
};


libfprint-aes1610-driver.patch:
 0 files changed

--- NEW FILE libfprint-aes1610-driver.patch ---


Index: libfprint.spec
===================================================================
RCS file: /cvs/pkgs/rpms/libfprint/F-12/libfprint.spec,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -p -r1.26 -r1.27
--- libfprint.spec	1 Oct 2009 14:15:42 -0000	1.26
+++ libfprint.spec	30 Nov 2009 11:07:29 -0000	1.27
@@ -1,6 +1,6 @@
 Name:           libfprint
 Version:        0.1.0
-Release:        12.pre2%{?dist}
+Release:        13.pre2%{?dist}
 Summary:        Tool kit for fingerprint scanner
 
 Group:          System Environment/Libraries
@@ -12,6 +12,9 @@ BuildRoot:      %{_tmppath}/%{name}-%{ve
 Patch1:		0001-Add-udev-rules-to-set-devices-to-autosuspend.patch
 # https://bugzilla.redhat.com/show_bug.cgi?id=472103
 Patch2:		0001-Add-gdk-pixbuf-support.patch
+# https://bugzilla.redhat.com/show_bug.cgi?id=499732
+Source1:	aes1610.c
+Patch3:		libfprint-aes1610-driver.patch
 ExcludeArch:    s390 s390x
 
 BuildRequires:  libusb1-devel glib2-devel gtk2-devel openssl-devel 
@@ -37,6 +40,8 @@ developing applications that use %{name}
 %setup -q -n %{name}-0.1.0-pre2
 %patch1 -p1
 %patch2 -p1
+cp -a %{SOURCE1} libfprint/drivers
+%patch3 -p1 -b .aes1610
 
 %build
 autoreconf -f -i
@@ -76,6 +81,9 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/pkgconfig/%{name}.pc
 
 %changelog
+* Mon Nov 30 2009 Bastien Nocera <bnocera at redhat.com> 0.1.0-13.pre2
+- Add aes1610 driver (#499732)
+
 * Thu Oct 01 2009 Bastien Nocera <bnocera at redhat.com> 0.1.0-12.pre2
 - Update udev autosuspend rules and disable SGS Thomson reader
 




More information about the scm-commits mailing list