/* * vfs301/vfs300 fingerprint reader driver * https://github.com/andree182/vfs301 * * Copyright (c) 2011-2012 Andrej Krutak * * 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); 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); 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 (); } } /* 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) { fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error); } /* 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_change_state (FpImageDevice *dev, FpiImageDeviceState state) { FpiSsm *ssm_loop; if (state != FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON) return; /* Start a capture operation. */ ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES); fpi_ssm_start (ssm_loop, 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->change_state = dev_change_state; img_class->bz3_threshold = 24; img_class->img_width = VFS301_FP_WIDTH; img_class->img_height = -1; }