libfprint/libfprint/drivers/vfs301.c
Bastien Nocera 197edac702 lib: Generate driver IDs, instead of hard-coding them
Instead of adding driver IDs by hand to a header file, generate the
driver ID from the (hopefully unique) name of the driver.

This means one file less for driver authors to modify, and one possible
source of merge conflicts less as well.

However, this means that already enrolled fingerprints will need to be
enrolled again, as the driver IDs will have changed compared to their
old on-disk value.
2019-06-12 16:50:01 +02:00

289 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_proto.h"
/************************** GENERIC STUFF *************************************/
/* Submit asynchronous sleep */
static void
async_sleep(unsigned int msec,
fpi_ssm *ssm,
struct fp_img_dev *dev)
{
/* Add timeout */
if (fpi_timeout_add(msec, fpi_ssm_next_state_timeout_cb, FP_DEV(dev), ssm) == NULL) {
/* Failed to add timeout */
fp_err("failed to add timeout");
fpi_imgdev_session_error(dev, -ETIME);
fpi_ssm_mark_failed(ssm, -ETIME);
}
}
static int
submit_image(fpi_ssm *ssm,
struct fp_img_dev *dev)
{
vfs301_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
int height;
struct fp_img *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 = fpi_img_new(VFS301_FP_OUTPUT_WIDTH * vdev->scanline_count);
if (img == NULL)
return 0;
vfs301_extract_image(vdev, 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 = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED;
img->width = VFS301_FP_OUTPUT_WIDTH;
img->height = height;
img = fpi_img_realloc(img, img->height * img->width);
fpi_imgdev_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(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
struct fp_img_dev *dev = user_data;
vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev);
switch (fpi_ssm_get_cur_state(ssm)) {
case M_REQUEST_PRINT:
vfs301_proto_request_fingerprint(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
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(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev))
fpi_ssm_jump_to_state(ssm, M_WAIT_PRINT);
else
fpi_ssm_next_state(ssm);
break;
case M_READ_PRINT_START:
fpi_imgdev_report_finger_status(dev, TRUE);
vfs301_proto_process_event_start(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
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(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
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_imgdev_report_finger_status(dev, FALSE);
} else {
fpi_ssm_jump_to_state(ssm, M_REQUEST_PRINT);
}
break;
}
}
/* Complete loop sequential state machine */
static void m_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
/* Free sequential state machine */
fpi_ssm_free(ssm);
}
/* Exec init sequential state machine */
static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
struct fp_img_dev *dev = user_data;
vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev);
g_assert(fpi_ssm_get_cur_state(ssm) == 0);
vfs301_proto_init(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
fpi_ssm_mark_completed(ssm);
}
/* Complete init sequential state machine */
static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
struct fp_img_dev *dev = user_data;
fpi_ssm *ssm_loop;
if (!fpi_ssm_get_error(ssm)) {
/* Notify activate complete */
fpi_imgdev_activate_complete(dev, 0);
/* Start loop ssm */
ssm_loop = fpi_ssm_new(FP_DEV(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 int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
{
fpi_ssm *ssm;
/* Start init ssm */
ssm = fpi_ssm_new(FP_DEV(dev), m_init_state, 1, dev);
fpi_ssm_start(ssm, m_init_complete);
return 0;
}
/* Deactivate device */
static void dev_deactivate(struct fp_img_dev *dev)
{
vfs301_dev_t *vdev;
vdev = FP_INSTANCE_DATA(FP_DEV(dev));
vfs301_proto_deinit(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
fpi_imgdev_deactivate_complete(dev);
}
static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
{
vfs301_dev_t *vdev = NULL;
int r;
/* Claim usb interface */
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
if (r < 0) {
/* Interface not claimed, return error */
fp_err("could not claim interface 0: %s", libusb_error_name(r));
return r;
}
/* Initialize private structure */
vdev = g_malloc0(sizeof(vfs301_dev_t));
fp_dev_set_instance_data(FP_DEV(dev), vdev);
vdev->scanline_buf = malloc(0);
vdev->scanline_count = 0;
/* Notify open complete */
fpi_imgdev_open_complete(dev, 0);
return 0;
}
static void dev_close(struct fp_img_dev *dev)
{
vfs301_dev_t *vdev;
/* Release private structure */
vdev = FP_INSTANCE_DATA(FP_DEV(dev));
free(vdev->scanline_buf);
g_free(vdev);
/* Release usb interface */
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
/* Notify close complete */
fpi_imgdev_close_complete(dev);
}
/* Usb id table of device */
static const struct usb_id id_table[] =
{
{ .vendor = 0x138a, .product = 0x0005 /* vfs301 */ },
{ .vendor = 0x138a, .product = 0x0008 /* vfs300 */ },
{ 0, 0, 0, },
};
/* Device driver definition */
struct fp_img_driver vfs301_driver =
{
/* Driver specification */
.driver =
{
.name = FP_COMPONENT,
.full_name = "Validity VFS301",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
/* Image specification */
.flags = 0,
.img_width = VFS301_FP_WIDTH,
.img_height = -1,
.bz3_threshold = 24,
/* Routine specification */
.open = dev_open,
.close = dev_close,
.activate = dev_activate,
.deactivate = dev_deactivate,
};