ff67bf5a16
Add a GCancellable parameter to fpi_ssm_nex_state_delayed and fpi_ssm_jump_to_state_delayed() so that it's possible to cancel an action from the caller and in case the driver wants to cancel a delayed operation when a device action has been cancelled.
281 lines
7 KiB
C
281 lines
7 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 *************************************/
|
|
|
|
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)
|
|
{
|
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
|
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 */
|
|
fpi_ssm_next_state_delayed (ssm, 200, NULL);
|
|
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 */
|
|
fpi_ssm_next_state_delayed (ssm, 200, NULL);
|
|
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, GError *error)
|
|
{
|
|
if (error)
|
|
{
|
|
g_warning ("State machine completed with an error: %s", error->message);
|
|
g_error_free (error);
|
|
}
|
|
/* Free sequential state machine */
|
|
}
|
|
|
|
/* Exec init sequential state machine */
|
|
static void
|
|
m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
|
{
|
|
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, 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);
|
|
fpi_ssm_start (ssm_loop, m_loop_complete);
|
|
}
|
|
|
|
/* Free sequential state machine */
|
|
}
|
|
|
|
/* Activate device */
|
|
static void
|
|
dev_activate (FpImageDevice *dev)
|
|
{
|
|
FpiSsm *ssm;
|
|
|
|
/* Start init ssm */
|
|
ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, 1);
|
|
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;
|
|
}
|