libfprint/libfprint/drivers/vfs301.c
2019-11-20 20:38:06 +01:00

298 lines
7.4 KiB
C

/*
* vfs301/vfs300 fingerprint reader driver
* https://github.com/andree182/vfs301
*
* Copyright (c) 2011-2012 Andrej Krutak <dev@andree.sk>
*
* 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 "vfs301"
#include "drivers_api.h"
#include "vfs301.h"
G_DEFINE_TYPE (FpDeviceVfs301, fpi_device_vfs301, FP_TYPE_IMAGE_DEVICE)
/************************** GENERIC STUFF *************************************/
/* Submit asynchronous sleep */
static void
async_sleep (unsigned int msec,
FpiSsm *ssm,
FpImageDevice *dev)
{
/* Add timeout */
fpi_device_add_timeout (FP_DEVICE (dev), msec,
fpi_ssm_next_state_timeout_cb, ssm);
}
static int
submit_image (FpiSsm *ssm,
FpImageDevice *dev)
{
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
int height;
FpImage *img;
#if 0
/* XXX: This is probably handled by libfprint automagically? */
if (vdev->scanline_count < 20)
{
fpi_ssm_jump_to_state (ssm, M_REQUEST_PRINT);
return 0;
}
#endif
img = fp_image_new (VFS301_FP_OUTPUT_WIDTH, self->scanline_count);
if (img == NULL)
return 0;
vfs301_extract_image (self, img->data, &height);
/* TODO: how to detect flip? should the resulting image be
* oriented so that it is equal e.g. to a fingerprint on a paper,
* or to the finger when I look at it?) */
img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED;
/* The image buffer is larger at this point, but that does not
* matter. */
img->width = VFS301_FP_OUTPUT_WIDTH;
img->height = height;
fpi_image_device_image_captured (dev, img);
return 1;
}
/* Loop ssm states */
enum {
/* Step 0 - Scan finger */
M_REQUEST_PRINT,
M_WAIT_PRINT,
M_CHECK_PRINT,
M_READ_PRINT_START,
M_READ_PRINT_WAIT,
M_READ_PRINT_POLL,
M_SUBMIT_PRINT,
/* Number of states */
M_LOOP_NUM_STATES,
};
/* Exec loop sequential state machine */
static void
m_loop_state (FpiSsm *ssm, FpDevice *_dev, void *user_data)
{
FpImageDevice *dev = user_data;
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev);
switch (fpi_ssm_get_cur_state (ssm))
{
case M_REQUEST_PRINT:
vfs301_proto_request_fingerprint (self);
fpi_ssm_next_state (ssm);
break;
case M_WAIT_PRINT:
/* Wait fingerprint scanning */
async_sleep (200, ssm, dev);
break;
case M_CHECK_PRINT:
if (!vfs301_proto_peek_event (self))
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
else
fpi_ssm_next_state (ssm);
break;
case M_READ_PRINT_START:
fpi_image_device_report_finger_status (dev, TRUE);
vfs301_proto_process_event_start (self);
fpi_ssm_next_state (ssm);
break;
case M_READ_PRINT_WAIT:
/* Wait fingerprint scanning */
async_sleep (200, ssm, dev);
break;
case M_READ_PRINT_POLL:
{
int rv = vfs301_proto_process_event_poll (self);
g_assert (rv != VFS301_FAILURE);
if (rv == VFS301_ONGOING)
fpi_ssm_jump_to_state (ssm, M_READ_PRINT_WAIT);
else
fpi_ssm_next_state (ssm);
}
break;
case M_SUBMIT_PRINT:
if (submit_image (ssm, dev))
{
fpi_ssm_mark_completed (ssm);
/* NOTE: finger off is expected only after submitting image... */
fpi_image_device_report_finger_status (dev, FALSE);
}
else
{
fpi_ssm_jump_to_state (ssm, M_REQUEST_PRINT);
}
break;
default:
g_assert_not_reached ();
}
}
/* Complete loop sequential state machine */
static void
m_loop_complete (FpiSsm *ssm, FpDevice *_dev, void *user_data,
GError *error)
{
if (error)
{
g_warning ("State machine completed with an error: %s", error->message);
g_error_free (error);
}
/* Free sequential state machine */
fpi_ssm_free (ssm);
}
/* Exec init sequential state machine */
static void
m_init_state (FpiSsm *ssm, FpDevice *_dev, void *user_data)
{
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev);
g_assert (fpi_ssm_get_cur_state (ssm) == 0);
vfs301_proto_init (self);
fpi_ssm_mark_completed (ssm);
}
/* Complete init sequential state machine */
static void
m_init_complete (FpiSsm *ssm, FpDevice *dev, void *user_data,
GError *error)
{
FpiSsm *ssm_loop;
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
if (!error)
{
/* Notify activate complete */
/* Start loop ssm */
ssm_loop = fpi_ssm_new (dev, m_loop_state,
M_LOOP_NUM_STATES, dev);
fpi_ssm_start (ssm_loop, m_loop_complete);
}
/* Free sequential state machine */
fpi_ssm_free (ssm);
}
/* Activate device */
static void
dev_activate (FpImageDevice *dev)
{
FpiSsm *ssm;
/* Start init ssm */
ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, 1, dev);
fpi_ssm_start (ssm, m_init_complete);
}
/* Deactivate device */
static void
dev_deactivate (FpImageDevice *dev)
{
FpDeviceVfs301 *self;
self = FPI_DEVICE_VFS301 (dev);
vfs301_proto_deinit (self);
fpi_image_device_deactivate_complete (dev, NULL);
}
static void
dev_open (FpImageDevice *dev)
{
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
GError *error = NULL;
/* Claim usb interface */
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
/* Initialize private structure */
self->scanline_count = 0;
/* Notify open complete */
fpi_image_device_open_complete (dev, error);
}
static void
dev_close (FpImageDevice *dev)
{
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
GError *error = NULL;
/* Release private structure */
g_clear_pointer (&self->scanline_buf, g_free);
/* Release usb interface */
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
0, 0, &error);
/* Notify close complete */
fpi_image_device_close_complete (dev, error);
}
/* Usb id table of device */
static const FpIdEntry id_table[] = {
{ /* vfs301 */ .vid = 0x138a, .pid = 0x0005, },
{ /* vfs300 */ .vid = 0x138a, .pid = 0x0008, },
{ .vid = 0, .pid = 0, .driver_data = 0 },
};
static void
fpi_device_vfs301_init (FpDeviceVfs301 *self)
{
}
static void
fpi_device_vfs301_class_init (FpDeviceVfs301Class *klass)
{
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
dev_class->id = "vfs301";
dev_class->full_name = "Validity VFS301";
dev_class->type = FP_DEVICE_TYPE_USB;
dev_class->id_table = id_table;
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
img_class->img_open = dev_open;
img_class->img_close = dev_close;
img_class->activate = dev_activate;
img_class->deactivate = dev_deactivate;
img_class->bz3_threshold = 24;
img_class->img_width = VFS301_FP_WIDTH;
img_class->img_height = -1;
}