libfprint/libfprint/drivers/validity/validity.h
2026-04-22 03:06:34 +00:00

346 lines
9.9 KiB
C

/*
* Validity/Synaptics VCSFW fingerprint sensor driver
*
* Copyright (C) 2024 libfprint contributors
*
* 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
*/
#pragma once
#include "fpi-device.h"
#include "fpi-ssm.h"
#include "validity_capture.h"
#include "validity_data.h"
#include "validity_db.h"
#include "validity_pair.h"
#include "validity_sensor.h"
#include "validity_tls.h"
/* USB Endpoint addresses */
#define VALIDITY_EP_CMD_OUT 0x01
#define VALIDITY_EP_CMD_IN 0x81
#define VALIDITY_EP_DATA_IN 0x82
#define VALIDITY_EP_INT_IN 0x83
/* USB transfer parameters */
#define VALIDITY_USB_TIMEOUT 15000
#define VALIDITY_USB_INT_TIMEOUT 100
#define VALIDITY_MAX_TRANSFER_LEN (100 * 1024)
#define VALIDITY_USB_INT_DATA_SIZE 1024
#define VALIDITY_USB_SEND_HEADER_LEN 1
/* Number of enroll stages */
#define VALIDITY_ENROLL_STAGES 8
/* Interrupt response bits */
#define VALIDITY_INT_FINGER_DOWN 0x02
#define VALIDITY_INT_SCAN_COMPLETE 0x04
typedef enum {
VALIDITY_DEV_90 = 0, /* 138a:0090 */
VALIDITY_DEV_97, /* 138a:0097 */
VALIDITY_DEV_9A, /* 06cb:009a */
VALIDITY_DEV_9D, /* 138a:009d */
} ValidityDeviceType;
/* Firmware version info from GET_VERSION (cmd 0x01) */
typedef struct
{
guint32 build_time;
guint32 build_num;
guint8 version_major;
guint8 version_minor;
guint8 target;
guint8 product;
guint8 silicon_rev;
guint8 formal_release;
guint8 platform;
guint8 patch;
guint8 serial_number[6];
guint16 security;
guint8 iface;
guint8 device_type;
} ValidityVersionInfo;
/* Open SSM states */
typedef enum {
VALIDITY_OPEN_CLAIM_INTERFACE = 0,
VALIDITY_OPEN_SEND_INIT,
VALIDITY_OPEN_NUM_STATES,
} ValidityOpenState;
/* Close SSM states */
typedef enum {
VALIDITY_CLOSE_RELEASE_INTERFACE = 0,
VALIDITY_CLOSE_NUM_STATES,
} ValidityCloseState;
/* Calibration SSM states (runs during open, after capture_setup) */
typedef enum {
CALIB_BUILD_CMD = 0,
CALIB_SEND_CMD,
CALIB_SEND_CMD_RECV,
CALIB_READ_DATA,
CALIB_AVERAGE_FRAMES,
CALIB_PROCESS,
CALIB_LOOP_CHECK,
CALIB_BUILD_CLEAN_SLATE_CMD,
CALIB_CLEAN_SLATE_SEND,
CALIB_CLEAN_SLATE_RECV,
CALIB_CLEAN_SLATE_READ,
CALIB_SAVE_CLEAN_SLATE,
CALIB_DONE,
CALIB_NUM_STATES,
} ValidityCalibState;
/* Enrollment SSM states — matches python-validity sensor.py Sensor.enroll() */
typedef enum {
ENROLL_CLEANUP_STALE = 0, /* Close any stale enrollment session */
ENROLL_CLEANUP_STALE_RECV,
/* Pre-enrollment: delete existing user records to avoid 0x0526 */
ENROLL_PRE_GET_STORAGE,
ENROLL_PRE_GET_STORAGE_RECV,
ENROLL_PRE_DEL_USER,
ENROLL_PRE_DEL_USER_RECV,
ENROLL_START, /* create_enrollment (cmd 0x69 flag=1) */
ENROLL_START_RECV,
/* --- Per-iteration loop --- */
ENROLL_LED_ON,
ENROLL_LED_ON_RECV,
ENROLL_WAIT_FINGER_DELAY,
ENROLL_BUILD_CAPTURE,
ENROLL_CAPTURE_SEND,
ENROLL_CAPTURE_RECV,
ENROLL_WAIT_FINGER,
ENROLL_WAIT_SCAN_COMPLETE,
ENROLL_GET_PRG_STATUS,
ENROLL_GET_PRG_STATUS_RECV,
ENROLL_CAPTURE_STOP,
ENROLL_CAPTURE_STOP_RECV,
ENROLL_UPDATE_START,
ENROLL_UPDATE_START_RECV,
ENROLL_WAIT_UPDATE_START_INT, /* PY: usb.wait_int() inside enrollment_update_start */
ENROLL_DB_WRITE_ENABLE, /* PY: write_enable() before 1st enrollment_update */
ENROLL_DB_WRITE_ENABLE_RECV,
ENROLL_APPEND_IMAGE, /* 1st enrollment_update (trigger) */
ENROLL_APPEND_IMAGE_RECV,
ENROLL_CLEANUPS, /* PY: call_cleanups() after 1st enrollment_update */
ENROLL_CLEANUPS_RECV,
ENROLL_WAIT_UPDATE_INT, /* PY: usb.wait_int() between the two calls */
ENROLL_DB_WRITE_ENABLE_READ, /* PY: write_enable() before 2nd enrollment_update */
ENROLL_DB_WRITE_ENABLE_READ_RECV,
ENROLL_APPEND_IMAGE_READ, /* 2nd enrollment_update (read result) */
ENROLL_APPEND_IMAGE_READ_RECV,
ENROLL_CLEANUPS_READ, /* PY: call_cleanups() after 2nd enrollment_update */
ENROLL_CLEANUPS_READ_RECV,
ENROLL_UPDATE_END, /* PY: enrollment_update_end = cmd 0x69 flag=0 (finally) */
ENROLL_UPDATE_END_RECV,
ENROLL_LOOP_CHECK,
/* --- Post-loop: DB commit --- */
ENROLL_UPDATE_END2, /* PY: 2nd enrollment_update_end after loop */
ENROLL_UPDATE_END2_RECV,
ENROLL_GET_STORAGE,
ENROLL_GET_STORAGE_RECV,
/* If storage doesn't exist (0x04b3), create it: */
ENROLL_INIT_STORAGE_WE, /* db_write_enable for storage creation */
ENROLL_INIT_STORAGE_WE_RECV,
ENROLL_INIT_STORAGE_CREATE, /* new_record(1, 4, 3, "StgWindsor\0") */
ENROLL_INIT_STORAGE_CREATE_RECV,
ENROLL_INIT_STORAGE_CLEAN, /* call_cleanups */
ENROLL_INIT_STORAGE_CLEAN_RECV,
ENROLL_DB_WRITE_ENABLE2,
ENROLL_DB_WRITE_ENABLE2_RECV,
ENROLL_CREATE_USER,
ENROLL_CREATE_USER_RECV,
ENROLL_CREATE_USER_CLEANUPS,
ENROLL_CREATE_USER_CLEANUPS_RECV,
ENROLL_DB_WRITE_ENABLE3,
ENROLL_DB_WRITE_ENABLE3_RECV,
ENROLL_CREATE_FINGER,
ENROLL_CREATE_FINGER_RECV,
ENROLL_FINAL_CLEANUPS,
ENROLL_FINAL_CLEANUPS_RECV,
ENROLL_WAIT_FINGER_INT,
ENROLL_LED_OFF, /* PY: glow_end_scan() — LAST step per PY */
ENROLL_LED_OFF_RECV,
ENROLL_DONE,
ENROLL_NUM_STATES,
} ValidityEnrollState;
/* Verify/Identify SSM states */
typedef enum {
VERIFY_LED_ON = 0,
VERIFY_LED_ON_RECV,
VERIFY_BUILD_CAPTURE,
VERIFY_CAPTURE_SEND,
VERIFY_CAPTURE_RECV,
VERIFY_WAIT_FINGER,
VERIFY_WAIT_SCAN_COMPLETE,
VERIFY_GET_PRG_STATUS,
VERIFY_GET_PRG_STATUS_RECV,
VERIFY_CAPTURE_STOP,
VERIFY_CAPTURE_STOP_RECV,
VERIFY_MATCH_START,
VERIFY_MATCH_START_RECV,
VERIFY_WAIT_MATCH_INT,
VERIFY_GET_RESULT,
VERIFY_GET_RESULT_RECV,
VERIFY_CLEANUP,
VERIFY_CLEANUP_RECV,
VERIFY_LED_OFF,
VERIFY_LED_OFF_RECV,
VERIFY_DONE,
VERIFY_NUM_STATES,
} ValidityVerifyState;
/* List prints SSM states */
typedef enum {
LIST_GET_STORAGE = 0,
LIST_GET_STORAGE_RECV,
LIST_GET_USER,
LIST_GET_USER_RECV,
LIST_DONE,
LIST_NUM_STATES,
} ValidityListState;
/* Delete print SSM states */
typedef enum {
DELETE_GET_STORAGE = 0,
DELETE_GET_STORAGE_RECV,
DELETE_LOOKUP_USER,
DELETE_LOOKUP_USER_RECV,
DELETE_DEL_RECORD,
DELETE_DEL_RECORD_RECV,
DELETE_DONE,
DELETE_NUM_STATES,
} ValidityDeleteState;
/* Clear storage SSM states */
typedef enum {
CLEAR_GET_STORAGE = 0,
CLEAR_GET_STORAGE_RECV,
CLEAR_DEL_USER,
CLEAR_DEL_USER_RECV,
CLEAR_DONE,
CLEAR_NUM_STATES,
} ValidityClearState;
#define FPI_TYPE_DEVICE_VALIDITY (fpi_device_validity_get_type ())
G_DECLARE_FINAL_TYPE (FpiDeviceValidity, fpi_device_validity,
FPI, DEVICE_VALIDITY, FpDevice)
struct _FpiDeviceValidity
{
FpDevice parent;
ValidityDeviceType dev_type;
ValidityVersionInfo version_info;
GCancellable *interrupt_cancellable;
/* Runtime data files loaded from libfprint-validity-data package */
ValidityDataStore device_data;
ValidityDataStore common_data;
/* TLS session state */
ValidityTlsState tls;
/* Sensor identification and HAL state (post-TLS) */
ValiditySensorState sensor;
/* Capture program infrastructure and calibration state */
ValidityCaptureState capture;
/* Firmware extension status */
gboolean fwext_loaded;
/* Pairing state (for uninitialized devices) */
ValidityPairState pair_state;
/* Calibration state */
gboolean calibrated;
guint calib_iteration;
/* Enrollment state */
guint32 enroll_key;
guint8 *enroll_template;
gsize enroll_template_len;
guint enroll_stage;
guint16 enroll_user_dbid;
guint16 enroll_storage_dbid;
guint scan_incomplete_count;
/* Verify/identify mode flag: TRUE = identify, FALSE = verify */
gboolean identify_mode;
/* List prints state */
ValidityUserStorage list_storage;
guint list_user_idx;
/* Delete state */
guint16 delete_storage_dbid;
guint16 delete_finger_subtype;
guint16 delete_finger_dbid;
/* Command SSM: manages the send-cmd/recv-response cycle */
FpiSsm *cmd_ssm;
/* Parent SSM: back-pointer for non-subsm child SSMs */
FpiSsm *open_ssm;
/* Pending response data stashed for higher-level SSM consumption */
guint16 cmd_response_status;
guint8 *cmd_response_data;
gsize cmd_response_len;
/* Bulk data buffer (EP 0x82 reads during capture/calibration) */
guint8 *bulk_data;
gsize bulk_data_len;
/* Emulation mode: in-memory print storage (element-type FpPrint) */
GPtrArray *emulation_prints;
};
/* Enrollment SSM (validity_enroll.c) */
void validity_enroll (FpDevice *device);
/* Enrollment response parsing — exposed for unit testing */
#define ENROLLMENT_MAGIC_LEN 0x38
typedef struct
{
guint8 *header;
gsize header_len;
guint8 *template_data;
gsize template_len;
guint8 *tid;
gsize tid_len;
} EnrollmentUpdateResult;
void enrollment_update_result_clear (EnrollmentUpdateResult *r);
gboolean parse_enrollment_update_response (const guint8 *data,
gsize data_len,
EnrollmentUpdateResult *result);
/* Verify/Identify SSMs (validity_verify.c) */
void validity_verify (FpDevice *device);
void validity_identify (FpDevice *device);
void validity_list (FpDevice *device);
void validity_delete (FpDevice *device);
void validity_clear_storage (FpDevice *device);
/* Gallery matching helper (validity_verify.c) */
FpPrint *validity_find_gallery_match (GPtrArray *gallery,
guint16 subtype);