There are minor changes to previously submitted driver.

Fixes:
* Setup bz3_threshold to 23 (works much more accurate)
* Replace USB_ENDPOINT_TYPE_ISOCHRONOUS by USB_RECIP_INTERFACE |
USB_ENDPOINT_OUT
* Remove awayt_finger_on (not implemented)
* Turn off led at dev_init() time
* FP_COMPONENT, before #include <fp_internal.h> statement
* Fixed goto read @ capture(): possible infinite loop
* Now driver use GLIB data types
* .id = 7 (is that correct?)
* RAW_IMAGE_{WIDTH|HEIGTH} changed to 398|301

TODO:
* Resample image (as is written in the spec)
* fix coding style ?
* Add -D_GNU_SOURCE to Makefile ( for memmem(3) )
* Testing (a.k.a Find some BUGS!)


DD, thanks for help!

-- 
Gustavo ChaĆ­n Dumit
http://0xff.cl
/*
 * Secugen FDU2000 driver for libfprint
 * Copyright (C) 2007 Gustavo Chain <[EMAIL PROTECTED]>
 *
 * 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
 */

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

#include <usb.h>

#define FP_COMPONENT "fdu2000"
#include <fp_internal.h>

#define BULK_TIMEOUT	200

/* fdu_req[] index */
typedef enum {
	CAPTURE_READY,
	CAPTURE_READ,
	CAPTURE_END,
	LED_OFF,
	LED_ON
} req_index;


#define CMD_LEN 2
#define ACK_LEN 8
static const struct fdu2000_req {
	const gchar cmd[CMD_LEN];	// Command to send
	const gchar ack[ACK_LEN];	// Expected ACK
	const guint ack_len;	// ACK has variable length
} fdu_req[] = {
	/* Capture */
	{
		.cmd = { 0x00, 0x04 },
		.ack = { 0x00, 0x04, 0x01, 0x01 },
		.ack_len = 4
	},
	
	{
		.cmd = { 0x00, 0x01 },
		.ack = { 0x00, 0x01, 0x01, 0x01 },
		.ack_len = 4
	},

	{
		.cmd = { 0x00, 0x05 },
		.ack = { 0x00, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
		.ack_len = 8
	},

	/* Led */
	{
		.cmd = { 0x05, 0x00 },
		.ack = {},
		.ack_len = 0
	},

	{
		.cmd = { 0x05, 0x01 },
		.ack = {},
		.ack_len = 0
	}
};

/*
 * Write a command and verify reponse
 */
static gint
bulk_write_safe(usb_dev_handle *dev, req_index rIndex) {

	gchar reponse[ACK_LEN];
	gint bytes, r;
	gchar *cmd = (gchar *)fdu_req[rIndex].cmd;
	gchar *ack = (gchar *)fdu_req[rIndex].ack;
	gint ack_len = fdu_req[rIndex].ack_len;

	bytes = usb_bulk_write(dev, USB_RECIP_INTERFACE | USB_ENDPOINT_OUT, cmd, sizeof(cmd), BULK_TIMEOUT);
	if (bytes < 0) {
		fp_err("%d: %s", __LINE__, usb_strerror());
	}

	if (ack_len == 0)
		return bytes;

	/* Check reply from FP */
	r = usb_bulk_read (dev, USB_ENDPOINT_DIR_MASK | USB_ENDPOINT_TYPE_ISOCHRONOUS,
			reponse, sizeof(reponse), BULK_TIMEOUT);
	if (r < 0) {
		fp_err(usb_strerror());
		return r;
	}

	if (!strncmp(ack, reponse, ack_len))
		return bytes;
	
	fp_err("%d: ACK ERROR!", __LINE__);
	return 0;
}

static gint
capture(struct fp_img_dev *dev, gboolean unconditional,
	struct fp_img **ret)
{
	/**
	 *  Pre resampled sizes
	 *  This sizes are taken directly from device
	 */
#define RAW_IMAGE_WIDTH		398
#define RAW_IMAGE_HEIGTH	301
#define RAW_IMAGE_SIZE		(RAW_IMAGE_WIDTH * RAW_IMAGE_HEIGTH)
	/**
	 *  Resampling sizes
	 *  Used for bilinear re-sampling
	 *  Not implemented, so, not used
	 */
#define SAMPLE_IMAGE_WIDTH	260
#define SAMPLE_IMAGE_HEIGTH	300
#define SAMPLE_IMAGE_SIZE	(SAMPLE_IMAGE_WIDTH * SAMPLE_IMAGE_HEIGTH)

	struct fp_img *img = NULL;
	guint bytes;
	const gchar SOF[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0c, 0x07 };  // Start of frame
	const gchar SOL[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0b, 0x06 };  // Start of line + { L L } (L: Line num) (8 nibbles)
	gchar *buffer;
	gchar *image;
	gchar *p;
	guint offset;

	img = fpi_img_new_for_imgdev(dev);

	buffer = g_malloc0(RAW_IMAGE_SIZE * 6);
	image  = g_malloc0(RAW_IMAGE_SIZE);

	bulk_write_safe(dev->udev, LED_ON);
	bulk_write_safe(dev->udev, CAPTURE_READY);
read:
	bulk_write_safe(dev->udev, CAPTURE_READ);
	/* Now we are ready to read from dev */

	bytes = usb_bulk_read(dev->udev,
			USB_ENDPOINT_DIR_MASK | USB_ENDPOINT_TYPE_BULK,
			buffer, RAW_IMAGE_SIZE * 6,
			BULK_TIMEOUT * 10);

	/*
	 * Find SOF (start of line)
	 */
	p = memmem(buffer, RAW_IMAGE_SIZE * 6,
			SOF, sizeof SOF);
	fp_dbg("Read %d byte/s from dev", bytes);
	if (!p)
		goto read;

	p += sizeof SOF;

	int i = 0;
	bytes = 0;
	while(p) {
		if ( i >= RAW_IMAGE_HEIGTH )
			break;

		offset = p - buffer;
		p = memmem(p, (RAW_IMAGE_SIZE * 6) - (offset),
				SOL, sizeof SOL);
		if (p) {
			p += sizeof SOL + 4;
			int j;
			for (j = 0; j < RAW_IMAGE_WIDTH; j++) {
				/**
				 * Convert from 4 to 8 bits
				 * The SECUGEN-FDU2000 has 4 lines of data, so we need to join 2 bytes into 1
				 */
				*(image + bytes + j)  = *(p + (j * 2) + 0) << 4 & 0xf0;
				*(image + bytes + j) |= *(p + (j * 2) + 1) & 0x0f;
			}
			p += RAW_IMAGE_WIDTH * 2;
			bytes += RAW_IMAGE_WIDTH;
			i++;
		}
	}

	memcpy(img->data, image, RAW_IMAGE_SIZE);
	img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
	*ret = img;

	bulk_write_safe(dev->udev, CAPTURE_END);
	bulk_write_safe(dev->udev, LED_OFF);

	g_free(buffer);
	g_free(image);

	return 0;

}

static
gint dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
	gint r;
	r = usb_set_configuration(dev->udev, 1);
	if (r < 0)
		goto hell;

	r = usb_claim_interface(dev->udev, USB_CLASS_PER_INTERFACE);
	if (r < 0)
		goto hell;

	r = usb_set_altinterface(dev->udev, 1);
	if (r < 0)
		goto hell;

	r = usb_clear_halt(dev->udev, USB_ENDPOINT_DIR_MASK | USB_ENDPOINT_TYPE_ISOCHRONOUS);
	if (r < 0)
		goto hell;

	/* Make sure sensor mode is not capture_{ready|read} */
	bulk_write_safe(dev->udev, CAPTURE_END);
	bulk_write_safe(dev->udev, LED_OFF);
	return 0;

hell:
	fp_err("could not init dev");
	fp_err(usb_strerror());
	return r;
}

static
void dev_exit(struct fp_img_dev *dev)
{
	gint r;
	
	bulk_write_safe(dev->udev, CAPTURE_END);
	r = usb_release_interface(dev->udev, USB_CLASS_PER_INTERFACE);
	if (r < 0)
		fp_err("could not release interface");
}

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

struct fp_img_driver fdu2000_driver = {
	.driver = {
		.id = 7,
		.name = FP_COMPONENT,
		.full_name = "Secugen FDU 2000",
		.id_table = id_table,
	},
	.img_height = RAW_IMAGE_HEIGTH,
	.img_width = RAW_IMAGE_WIDTH,
	.bz3_threshold = 23,

	.init = dev_init,
	.exit = dev_exit,
	.capture = capture,
};
_______________________________________________
fprint mailing list
[email protected]
http://lists.reactivated.net/mailman/listinfo/fprint

Reply via email to