El Tue, 18 Dec 2007 17:07:34 +0000
Daniel Drake <[EMAIL PROTECTED]> escribió:
> Gustavo Chain wrote:
> > 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
>
> That's not right constant usage either. USB_RECIP_INTERFACE is a
> constant designed for use in the bmRequestType field of control
> messages, not for endpoint addressing.
>
> Also there is still "constant abuse" in usb_bulk_read() and
> usb_clear_halt() and maybe other places too.
>
> > * Remove awayt_finger_on (not implemented)
>
> Seems to me that this should be on your TODO list, or maybe we should
> provide a generic one in the library which uses a histogram-like
> approach to detecting fingers.
By now, I will put it into TODO LIST
>
> > * .id = 7 (is that correct?)
so back to 99;
>
> I'll assign one at merge time, use whatever number you feel like for
> now.
>
> > TODO:
> > * Add -D_GNU_SOURCE to Makefile ( for memmem(3) )
>
> Is there a glib equivalent of memmem()? It seems like requiring
> GNU-specific libc extensions may hurt portability.
>
I've implemented memmem as a driver function.
> You should probably do error checking in bulk_write_safe() callers as
> this may help detect weird bugs early on in future.
Implemented as macro (may be isn't nice)
> Apart from that, it looks great. If you send a new revision with
> those changes I'm happy include it and you can submit the later items
> as patches.
>
> BTW: in the development branch (fpusb), all drivers have to be
> converted to use async USB I/O which unfortunately adds a little
> driver complexity which I'm working to minimize. I'm happy to do the
> porting but you will need to test the new version at some point :)
>
> Thanks!
> Daniel
--
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>
#ifndef HAVE_MEMMEM
gpointer
memmem(const gpointer haystack, size_t haystack_len, const gpointer needle, size_t needle_len) {
const gchar *begin;
const char *const last_possible = (const char *) haystack + haystack_len - needle_len;
/* The first occurrence of the empty string is deemed to occur at
* the beginning of the string. */
if (needle_len == 0)
return (void *) haystack;
/* Sanity check, otherwise the loop might search through the whole
* memory. */
if (haystack_len < needle_len)
return NULL;
for (begin = (const char *) haystack; begin <= last_possible; ++begin)
if (begin[0] == ((const char *) needle)[0] &&
!memcmp((const void *) &begin[1],
(const void *) ((const char *) needle + 1),
needle_len - 1))
return (void *) begin;
return NULL;
}
#endif /* HAVE_MEMMEM */
#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 r;
gchar *cmd = (gchar *)fdu_req[rIndex].cmd;
gchar *ack = (gchar *)fdu_req[rIndex].ack;
gint ack_len = fdu_req[rIndex].ack_len;
r = usb_bulk_write(dev, 0x01 | USB_ENDPOINT_OUT, cmd, sizeof(cmd), BULK_TIMEOUT);
if (r < 0) {
return r;
}
/* No expected ACK, return */
if (ack_len == 0)
return 0;
/* Check reply from FP */
r = usb_bulk_read (dev, 0x01 | USB_ENDPOINT_DIR_MASK,
reponse, sizeof(reponse), BULK_TIMEOUT);
if (r < 0) {
fp_err(usb_strerror());
return r;
}
if (!strncmp(ack, reponse, ack_len))
return 0;
fp_err("Expected different ACK from dev");
return 1;
}
#define BULK_WRITE(x, e) do { \
r = bulk_write_safe(dev->udev, x); \
if (r != 0) { \
fp_err("%s failed", e); \
goto out; \
} \
} while(0)
static gint
capture(struct fp_img_dev *dev, gboolean unconditional,
struct fp_img **ret)
{
#define RAW_IMAGE_WIDTH 398
#define RAW_IMAGE_HEIGTH 301
#define RAW_IMAGE_SIZE (RAW_IMAGE_WIDTH * RAW_IMAGE_HEIGTH)
struct fp_img *img = NULL;
gint bytes, r;
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(LED_ON, "Turning Led ON");
BULK_WRITE(CAPTURE_READY, "Setting up CAPTURE_READY Mode");
BULK_WRITE(CAPTURE_READ, "Setting up CAPTURE_READ Mode");
/* Now we are ready to read from buffer */
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,
(const gpointer)SOF, sizeof SOF);
fp_dbg("Read %d byte/s from dev", bytes);
if (!p)
goto out;
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),
(const gpointer)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(CAPTURE_END, "Setting up CAPTURE_END mode");
BULK_WRITE(LED_OFF, "Turning off LED");
out:
g_free(buffer);
g_free(image);
return r;
}
static
gint dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
gint r;
r = usb_set_configuration(dev->udev, 0x01);
if (r < 0)
goto out;
r = usb_claim_interface(dev->udev, USB_CLASS_PER_INTERFACE);
if (r < 0)
goto out;
r = usb_set_altinterface(dev->udev, 0x01);
if (r < 0)
goto out;
r = usb_clear_halt(dev->udev, 0x01 | USB_ENDPOINT_DIR_MASK);
if (r < 0)
goto out;
/* Make sure sensor mode is not capture_{ready|read} */
BULK_WRITE(CAPTURE_END, "Setting CAPTURE_END mode");
BULK_WRITE(LED_OFF, "Turning Led OFF");
return 0;
out:
fp_err("could not init dev");
fp_err(usb_strerror());
return r;
}
static
void dev_exit(struct fp_img_dev *dev)
{
gint r;
r = bulk_write_safe(dev->udev, CAPTURE_END);
/* We are quitting, so just inform the error */
if (r != 0)
fp_err("Setting CAPTURE_END mode");
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 = 99,
.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