rpms/libfprint/F-12 libfprint-aes1610-driver.patch, 1.1, 1.2 libfprint.spec, 1.27, 1.28

Bastien Nocera hadess at fedoraproject.org
Tue Dec 1 14:28:13 UTC 2009


Author: hadess

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

Modified Files:
	libfprint-aes1610-driver.patch libfprint.spec 
Log Message:
* Tue Dec 01 2009 Bastien Nocera <bnocera at redhat.com> 0.1.0-14.pre2
- Update AES1610 patch (#499732)


libfprint-aes1610-driver.patch:
 configure.ac                |    2 
 libfprint/Makefile.am       |    6 
 libfprint/core.c            |    4 
 libfprint/drivers/aes1610.c | 1040 ++++++++++++++++++++++++++++++++++----------
 4 files changed, 815 insertions(+), 237 deletions(-)

Index: libfprint-aes1610-driver.patch
===================================================================
RCS file: /cvs/pkgs/rpms/libfprint/F-12/libfprint-aes1610-driver.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -p -r1.1 -r1.2
--- libfprint-aes1610-driver.patch	30 Nov 2009 11:07:29 -0000	1.1
+++ libfprint-aes1610-driver.patch	1 Dec 2009 14:28:12 -0000	1.2
@@ -0,0 +1,1254 @@
+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 at users.sourceforge.net>
+- * Copyright (C) 2007 Daniel Drake <dsd at gentoo.org>
++ * Copyright (C) 2007-2008 Daniel Drake <dsd at gentoo.org>
+  * Copyright (C) 2007 Cyrille Bagard
+  * Copyright (C) 2007 Vasily Khoruzhick
++ * Copyright (C) 2009 Guido Grazioli <guido.grazioli at 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)
++	fpi_imgdev_report_finger_status(dev, FALSE);
++	start_finger_detection(dev);
++}
++
++static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
++{
++	struct libusb_transfer *transfer;
++	unsigned char *data;
++	int r;
++
++	if (result) {
++		fpi_imgdev_session_error(dev, result);
++		return;
++	}
++
++	transfer = libusb_alloc_transfer(0);
++	if (!transfer) {
++		fpi_imgdev_session_error(dev, -ENOMEM);
++		return;
++	}
++
++	data = g_malloc(19);
++	libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 19,
++		finger_det_data_cb, dev, BULK_TIMEOUT);
++
++	r = libusb_submit_transfer(transfer);
++	if (r < 0) {
++		g_free(data);
++		libusb_free_transfer(transfer);
++		fpi_imgdev_session_error(dev, r);
++	}
++
++}
++
++static void start_finger_detection(struct fp_img_dev *dev)
++{
++	struct aes1610_dev *aesdev = dev->priv;
++	struct libusb_transfer *transfer;
++
++	if (aesdev->deactivating) {
++		complete_deactivation(dev);
++		return;
++	}
++
++	aes_write_regv(dev, finger_det_reqs, G_N_ELEMENTS(finger_det_reqs), finger_det_reqs_cb, NULL);
++
++}
++
++/****** CAPTURE ******/
++
++static struct aes_regwrite capture_reqs[] = {
+ 	{ 0x80, 0x01 },
+ 	{ 0x80, 0x12 },
+ 	{ 0x84, 0x01 },
+@@ -271,8 +523,8 @@ static const struct aes_regwrite capture_reqs[] = {
+ 	{ 0x8B, 0x0E },
+ 	{ 0x8C, 0x90 },
+ 	{ 0xBE, 0x23 },
+-	{ 0x29, 0x06 },
+-	{ 0x2A, 0x35 },
++	{ 0x29, 0x04 },
++	{ 0x2A, 0xFF },
+ 	{ 0x96, 0x00 },
+ 	{ 0x98, 0x03 },
+ 	{ 0x99, 0x00 },
+@@ -387,10 +639,10 @@ static const struct aes_regwrite capture_reqs[] = {
+ 	{ 0x81, 0x01 }
+ };
+ 
+-static const struct aes_regwrite strip_scan_reqs[] = {
++static struct aes_regwrite strip_scan_reqs[] = {
+ 	{ 0xBE, 0x23 },
+-	{ 0x29, 0x06 },
+-	{ 0x2A, 0x35 },
++	{ 0x29, 0x04 },
++	{ 0x2A, 0xFF },
+ 	{ 0xBD, 0x4F },
+ 	{ 0xFF, 0x00 }
+ };
+@@ -399,130 +651,456 @@ static const struct aes_regwrite capture_stop[] = {
+ 	{ 0x81,0x00 }
+ };
+ 
+-static int capture(struct fp_img_dev *dev, gboolean unconditional,
+-	struct fp_img **ret)
++/*
++ * The different possible values for 0xBE register */
++static unsigned char list_BE_values[10] = {
++	0x23, 0x43, 0x63, 0x64, 0x65, 0x67, 0x6A, 0x6B
++};
++
++/*
++ * The different possible values for 0xBD register */
++static unsigned char list_BD_values[10] = {
++	0x48, 0x4B, 0x4F, 0x52, 0x57, 0x59, 0x5B
++};
++
++/*
++ * Adjust the gain according to the histogram data
++ * 0xbd, 0xbe, 0x29 and 0x2A registers are affected
++ * Returns 0 if no problem occured
++ * TODO: This is a basic support for gain. It needs testing/tweaking.  */
++static int adjust_gain(unsigned char *buffer, int status)
+ {
+-	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;
++	// The position in the array of possible values for 0xBE and 0xBD registers
++	static int pos_list_BE = 0;
++	static int pos_list_BD = 0;
+ 
+-	/* FIXME can do better here in terms of buffer management? */
+-	fp_dbg("");
++	// This is the first adjustement (we begin acquisition)
++	// We adjust strip_scan_reqs for future strips and capture_reqs that is sent just after this step
++	if (status == GAIN_STATUS_FIRST) {
++		if (buffer[1] > 0x78) { // maximum gain needed
++			strip_scan_reqs[0].value = 0x6B;
++			strip_scan_reqs[1].value = 0x06;
++			strip_scan_reqs[2].value = 0x35;
++			strip_scan_reqs[3].value = 0x5B;
++		}
++		else if (buffer[1] > 0x55) {
++			strip_scan_reqs[0].value = 0x63;
++			strip_scan_reqs[1].value = 0x15;
++			strip_scan_reqs[2].value = 0x35;
++			strip_scan_reqs[3].value = 0x4F;
++		}
++		else if (buffer[1] > 0x40 || buffer[16] > 0x19) {
++			strip_scan_reqs[0].value = 0x43;
++			strip_scan_reqs[1].value = 0x13;
++			strip_scan_reqs[2].value = 0x35;
++			strip_scan_reqs[3].value = 0x4B;
++		}
++		else { // minimum gain needed
++			strip_scan_reqs[0].value = 0x23;
++			strip_scan_reqs[1].value = 0x07;
++			strip_scan_reqs[2].value = 0x35;
++			strip_scan_reqs[3].value = 0x48;
++		}
+ 
+-	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) */
++		// Now copy this values in capture_reqs
++		capture_reqs[8].value = strip_scan_reqs[0].value;
++		capture_reqs[9].value = strip_scan_reqs[1].value;
++		capture_reqs[10].value = strip_scan_reqs[2].value;
++		capture_reqs[21].value = strip_scan_reqs[3].value;
+ 
+-	img = fpi_img_new((3 * MAX_FRAMES * FRAME_SIZE) / 2);
+-	imgptr = img->data;
+-	cooked = imgptr + (MAX_FRAMES * FRAME_SIZE) / 2;
++		fp_dbg("first gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
++	}
+ 
+-	r = read_data(dev, buf, 665);
+-	if (r < 0)
+-		goto err;
+-	memcpy(imgptr, buf + 1, 128*4);
+-	imgptr += 128*4;
++	// Every 2/3 strips
++	// We try to soften big changes of the gain (at least for 0xBE and 0xBD
++	// FIXME: This softenning will need testing and tweaking too
++	else if (status == GAIN_STATUS_NORMAL) {
++		if (buffer[514] > 0x78) { // maximum gain needed
++			if (pos_list_BE < 7)
++				pos_list_BE++;
+ 
+-	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 (pos_list_BD < 6)
++				pos_list_BD++;
++
++			strip_scan_reqs[1].value = 0x04;
++			strip_scan_reqs[2].value = 0x35;
++		}
++		else if (buffer[514] > 0x55) {
++			if (pos_list_BE < 2)
++				pos_list_BE++;
++			else if (pos_list_BE > 2)
++				pos_list_BE--;
++
++			if (pos_list_BD < 2)
++				pos_list_BD++;
++			else if (pos_list_BD > 2)
++				pos_list_BD--;
++
++			strip_scan_reqs[1].value = 0x15;
++			strip_scan_reqs[2].value = 0x35;
+ 		}
+-		if (sum < 0) {
+-			r = sum;
+-			goto err;
++		else if (buffer[514] > 0x40 || buffer[529] > 0x19) {
++			if (pos_list_BE < 1)
++				pos_list_BE++;
++			else if (pos_list_BE > 1)
++				pos_list_BE--;
++
++			if (pos_list_BD < 1)
++				pos_list_BD++;
++			else if (pos_list_BD > 1)
++				pos_list_BD--;
++
++			strip_scan_reqs[1].value = 0x13;
++			strip_scan_reqs[2].value = 0x35;
+ 		}
+-		fp_dbg("sum=%d", sum);
+-		if (sum == 0)
+-			count_blank++;
++		else { // minimum gain needed
++			if (pos_list_BE > 0)
++				pos_list_BE--;
++
++			if (pos_list_BD > 0)
++				pos_list_BD--;
++
++			strip_scan_reqs[1].value = 0x07;
++			strip_scan_reqs[2].value = 0x35;
++		}
++
++		strip_scan_reqs[0].value = list_BE_values[pos_list_BE];
++		strip_scan_reqs[3].value = list_BD_values[pos_list_BD];
++
++		fp_dbg("gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
++	}
++	// Unknown status
++	else {
++		fp_err("Unexpected gain status.");
++		return 1;
++	}
++
++	return 0;
++}
++
++/*
++ * Restore the default gain values */
++static void restore_gain()
++{
++	strip_scan_reqs[0].value = list_BE_values[0];
++	strip_scan_reqs[1].value = 0x04;
++	strip_scan_reqs[2].value = 0xFF;
++	strip_scan_reqs[3].value = list_BD_values[0];
++
++	capture_reqs[8].value = list_BE_values[0];
++	capture_reqs[9].value = 0x04;
++	capture_reqs[10].value = 0xFF;
++	capture_reqs[21].value = list_BD_values[0];
++}
++
++
++/* capture SM movement:
++ * request and read strip,
++ * jump back to request UNLESS theres no finger, in which case exit SM,
++ * report lack of finger presence, and move to finger detection */
++
++enum capture_states {
++	CAPTURE_WRITE_REQS,
++	CAPTURE_READ_DATA,
++	CAPTURE_REQUEST_STRIP,
++	CAPTURE_READ_STRIP,
++	CAPTURE_NUM_STATES,
++};
++
++static void capture_read_strip_cb(struct libusb_transfer *transfer)
++{
++	unsigned char *stripdata;
++	struct fpi_ssm *ssm = transfer->user_data;
++	struct fp_img_dev *dev = ssm->priv;
++	struct aes1610_dev *aesdev = dev->priv;
++	unsigned char *data = transfer->buffer;
++	int sum, i;
++	int threshold;
++
++	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
++		fpi_ssm_mark_aborted(ssm, -EIO);
++		goto out;
++	} else if (transfer->length != transfer->actual_length) {
++		fpi_ssm_mark_aborted(ssm, -EPROTO);
++		goto out;
++	}
++
++	/* FIXME: would preallocating strip buffers be a decent optimization? */
++	//stripdata = g_malloc(128 * 4);
++	//memcpy(stripdata, data + 1, 128 * 4);
++	//aesdev->strips = g_slist_prepend(aesdev->strips, stripdata);
++	//aesdev->strips_len++;
++
++	/*threshold = regval_from_dump(data + 1 + 128*8 + 1 + 16*2 + 1 + 8,
++		0x97);
++	if (threshold < 0) {
++		fpi_ssm_mark_aborted(ssm, threshold);
++		goto out;
++	}*/
++
++	sum = 0;
++	for (i = 516; 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 += data[i];
++	}
++
++	if (sum > 0) {
++	        /* FIXME: would preallocating strip buffers be a decent optimization? */
++	        stripdata = g_malloc(128 * 4);
++	        memcpy(stripdata, data + 1, 128 * 4);
++	        aesdev->strips = g_slist_prepend(aesdev->strips, stripdata);
++	        aesdev->strips_len++;
++		aesdev->blanks_count = 0;
++	}
++
++	if (sum < 0) {
++		fpi_ssm_mark_aborted(ssm, sum);
++		goto out;
++	}
++	fp_dbg("sum=%d", sum);
++
++	/* FIXME: 0 might be too low as a threshold */
++	/* FIXME: sometimes we get 0 in the middle of a scan, should we wait for
++	 * a few consecutive zeroes? */
++
++	/* If sum is 0 for a reasonable # of frames, finger has been removed */
++	if (sum == 0) {
++		aesdev->blanks_count++;
++		fp_dbg("got blank frame");
++	}
++
++	/* use histogram data above for gain calibration (0xbd, 0xbe, 0x29 and 0x2A ) */
++	adjust_gain(data, GAIN_STATUS_NORMAL);
++
++	/* stop capturing if MAX_FRAMES is reached */
++	if (aesdev->blanks_count > 10 || g_slist_length(aesdev->strips) >= MAX_FRAMES) {
++		fp_dbg("sending stop capture.... blanks=%d  frames=%d", aesdev->blanks_count, g_slist_length(aesdev->strips));
++		/* send stop capture bits */
++		aes_write_regv(dev, capture_stop, G_N_ELEMENTS(capture_stop), stub_capture_stop_cb, NULL);
++		/* assemble image and submit it to library */
++		assemble_and_submit_image(dev);
++		fpi_imgdev_report_finger_status(dev, FALSE);
++		/* marking machine complete will re-trigger finger detection loop */
++		fpi_ssm_mark_completed(ssm);
++		/* Acquisition finished: restore default gain values */
++		restore_gain();
++	} else {
++		/* obtain next strip */
++		fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
++	}
++
++out:
++	g_free(data);
++	libusb_free_transfer(transfer);
++}
++
++static void capture_run_state(struct fpi_ssm *ssm)
++{
++	struct fp_img_dev *dev = ssm->priv;
++	struct aes1610_dev *aesdev = dev->priv;
++	int r;
++
++	switch (ssm->cur_state) {
++	case CAPTURE_WRITE_REQS:
++		fp_dbg("write reqs");
++		aes_write_regv(dev, capture_reqs, G_N_ELEMENTS(capture_reqs),
++			generic_write_regv_cb, ssm);
++		break;
++	case CAPTURE_READ_DATA:
++		fp_dbg("read data");
++		generic_read_ignore_data(ssm, 665);
++		break;
++	case CAPTURE_REQUEST_STRIP:
++		fp_dbg("request strip");
++		if (aesdev->deactivating)
++			fpi_ssm_mark_completed(ssm);
+ 		else
+-			count_blank = 0;
+-			
+-		/* if we got 50 blank frames, assume scan has ended. */
+-		if (count_blank >= 50)
++			aes_write_regv(dev, strip_scan_reqs, G_N_ELEMENTS(strip_scan_reqs),
++				generic_write_regv_cb, ssm);
++		break;
++	case CAPTURE_READ_STRIP: ;
++		struct libusb_transfer *transfer = libusb_alloc_transfer(0);
++		unsigned char *data;
++
++		if (!transfer) {
++			fpi_ssm_mark_aborted(ssm, -ENOMEM);
+ 			break;
++		}
++
++		data = g_malloc(665);
++		libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 665,
++			capture_read_strip_cb, ssm, BULK_TIMEOUT);
++
++		r = libusb_submit_transfer(transfer);
++		if (r < 0) {
++			g_free(data);
++			libusb_free_transfer(transfer);
++			fpi_ssm_mark_aborted(ssm, r);
++		}
++		break;
++	};
++}
++
++static void capture_sm_complete(struct fpi_ssm *ssm)
++{
++	struct fp_img_dev *dev = ssm->priv;
++	struct aes1610_dev *aesdev = dev->priv;
++
++	fp_dbg("");
++	if (aesdev->deactivating)
++		complete_deactivation(dev);
++	else if (ssm->error)
++		fpi_imgdev_session_error(dev, ssm->error);
++	else
++		start_finger_detection(dev);
++	fpi_ssm_free(ssm);
++}
++
++static void start_capture(struct fp_img_dev *dev)
++{
++	struct aes1610_dev *aesdev = dev->priv;
++	struct fpi_ssm *ssm;
++
++	if (aesdev->deactivating) {
++		complete_deactivation(dev);
++		return;
+ 	}
+-	
+-	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?");
++	ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
++	fp_dbg("");
++	ssm->priv = dev;
++	fpi_ssm_start(ssm, capture_sm_complete);
++}
+ 
+-	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");
++/****** INITIALIZATION/DEINITIALIZATION ******/
++
++static const struct aes_regwrite init[] = {
++	{ 0x82, 0x00 }
++};
++
++static const struct aes_regwrite stop_reader[] = {
++	{ 0xFF, 0x00 }
++};
++
++
++enum activate_states {
++	WRITE_INIT,
++//	READ_DATA,
++//	READ_REGS,
++	ACTIVATE_NUM_STATES,
++};
++
++/* this come from aes2501 and is unused here
++void activate_read_regs_cb(struct fp_img_dev *dev, int status,
++	unsigned char *regs, void *user_data)
++{
++	struct fpi_ssm *ssm = user_data;
++	struct aes1610_dev *aesdev = dev->priv;
++
++	if (status != 0) {
++		fpi_ssm_mark_aborted(ssm, status);
+ 	} else {
+-		fp_dbg("reversed scan direction");
++		fpi_ssm_next_state(ssm);
+ 	}
++}
++*/
+ 
+-	final_size = img->height * FRAME_WIDTH;
+-	memcpy(img->data, cooked, final_size);
+-	img = fpi_img_resize(img, final_size);
+-	*ret = img;
++static void activate_run_state(struct fpi_ssm *ssm)
++{
++	struct fp_img_dev *dev = ssm->priv;
++
++	/* activation on aes1610 seems much more straightforward compared to aes2501 */
++	/* verify theres anything missing here */
++	switch (ssm->cur_state) {
++	case WRITE_INIT:
++		fp_dbg("write init");
++		aes_write_regv(dev, init, G_N_ELEMENTS(init), generic_write_regv_cb, ssm);
++		break;
++/*	case READ_DATA:
++		fp_dbg("read data");
++		generic_read_ignore_data(ssm, 20);
++		break;
++	case READ_REGS:
++		fp_dbg("read regs");
++		read_regs(dev, activate_read_regs_cb, ssm);
++		break;*/
++	}
++}
++
++/* jump to finger detection */
++static void activate_sm_complete(struct fpi_ssm *ssm)
++{
++	struct fp_img_dev *dev = ssm->priv;
++	fp_dbg("status %d", ssm->error);
++	fpi_imgdev_activate_complete(dev, ssm->error);
++
++	if (!ssm->error)
++		start_finger_detection(dev);
++	fpi_ssm_free(ssm);
++}
++
++static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
++{
++	struct aes1610_dev *aesdev = dev->priv;
++	struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
++		ACTIVATE_NUM_STATES);
++	ssm->priv = dev;
++	aesdev->read_regs_retry_count = 0;
++	fpi_ssm_start(ssm, activate_sm_complete);
+ 	return 0;
+-err:
+-	fp_img_free(img);
+-	return r;
++}
++
++static void dev_deactivate(struct fp_img_dev *dev)
++{
++	struct aes1610_dev *aesdev = dev->priv;
++	/* FIXME: audit cancellation points, probably need more, specifically
++	 * in error handling paths? */
++	aesdev->deactivating = TRUE;
++}
++
++static void complete_deactivation(struct fp_img_dev *dev)
++{
++	struct aes1610_dev *aesdev = dev->priv;
++	fp_dbg("");
++
++	/* FIXME: if we're in the middle of a scan, we should cancel the scan.
++	 * maybe we can do this with a master reset, unconditionally? */
++
++	aesdev->deactivating = FALSE;
++	g_slist_free(aesdev->strips);
++	aesdev->strips = NULL;
++	aesdev->strips_len = 0;
++	aesdev->blanks_count = 0;
++	fpi_imgdev_deactivate_complete(dev);
++}
++
++static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
++{
++	/* FIXME check endpoints */
++	int r;
++
++	r = libusb_claim_interface(dev->udev, 0);
++	if (r < 0) {
++		fp_err("could not claim interface 0");
++		return r;
++	}
++
++	dev->priv = g_malloc0(sizeof(struct aes1610_dev));
++	fpi_imgdev_open_complete(dev, 0);
++	return 0;
++}
++
++static void dev_deinit(struct fp_img_dev *dev)
++{
++	g_free(dev->priv);
++	libusb_release_interface(dev->udev, 0);
++	fpi_imgdev_close_complete(dev);
+ }
+ 
+ static const struct usb_id id_table[] = {
+-	{ .vendor = 0x08ff, .product = 0x1600 },
++	{ .vendor = 0x08ff, .product = 0x1600 }, /* AES1600 */
+ 	{ 0, 0, 0, },
+ };
+ 
+@@ -544,9 +1122,9 @@ struct fp_img_driver aes1610_driver = {
+ 	 * area) */
+ 	.bz3_threshold = 10,
+ 
+-	.init = dev_init,
+-	.exit = dev_exit,
+-	.await_finger_on = await_finger_on,
+-	.capture = capture,
++	.open = dev_init,
++	.close = dev_deinit,
++	.activate = dev_activate,
++	.deactivate = dev_deactivate,
+ };
+ 


Index: libfprint.spec
===================================================================
RCS file: /cvs/pkgs/rpms/libfprint/F-12/libfprint.spec,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -p -r1.27 -r1.28
--- libfprint.spec	30 Nov 2009 11:07:29 -0000	1.27
+++ libfprint.spec	1 Dec 2009 14:28:12 -0000	1.28
@@ -1,6 +1,6 @@
 Name:           libfprint
 Version:        0.1.0
-Release:        13.pre2%{?dist}
+Release:        14.pre2%{?dist}
 Summary:        Tool kit for fingerprint scanner
 
 Group:          System Environment/Libraries
@@ -81,6 +81,9 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/pkgconfig/%{name}.pc
 
 %changelog
+* Tue Dec 01 2009 Bastien Nocera <bnocera at redhat.com> 0.1.0-14.pre2
+- Update AES1610 patch (#499732)
+
 * Mon Nov 30 2009 Bastien Nocera <bnocera at redhat.com> 0.1.0-13.pre2
 - Add aes1610 driver (#499732)
 




More information about the scm-commits mailing list