From e5138488710072fd2faf001ac1be3a7e7621d009 Mon Sep 17 00:00:00 2001 From: Vincent Huang Date: Fri, 12 Apr 2019 11:47:15 +0800 Subject: [PATCH] Add Synaptics driver --- doc/meson.build | 1 + libfprint/drivers/driver_ids.h | 1 + libfprint/drivers/synaptics/include/bmkt.h | 981 ++++++++++++++++++ .../drivers/synaptics/include/bmkt_internal.h | 49 + .../drivers/synaptics/include/bmkt_message.h | 94 ++ .../drivers/synaptics/include/bmkt_response.h | 478 +++++++++ libfprint/drivers/synaptics/include/crc.h | 34 + libfprint/drivers/synaptics/include/event.h | 31 + libfprint/drivers/synaptics/include/mutex.h | 29 + .../include/platform/linux/platform.h | 53 + .../include/platform/posix/plat_thread.h | 30 + .../synaptics/include/platform/posix/posix.h | 31 + libfprint/drivers/synaptics/include/sensor.h | 91 ++ .../drivers/synaptics/include/synaptics.h | 67 ++ libfprint/drivers/synaptics/include/thread.h | 46 + .../synaptics/include/transport/transport.h | 89 ++ .../include/transport/usb_transport.h | 47 + libfprint/drivers/synaptics/src/auth.c | 64 ++ libfprint/drivers/synaptics/src/bmkt.c | 337 ++++++ .../drivers/synaptics/src/bmkt_message.c | 378 +++++++ libfprint/drivers/synaptics/src/crc.c | 231 +++++ libfprint/drivers/synaptics/src/enroll.c | 87 ++ .../synaptics/src/platform/linux/plat_event.c | 124 +++ .../synaptics/src/platform/linux/plat_log.c | 71 ++ .../synaptics/src/platform/posix/plat_mutex.c | 63 ++ .../src/platform/posix/plat_thread.c | 54 + .../synaptics/src/platform/posix/posix.c | 72 ++ libfprint/drivers/synaptics/src/sensor.c | 653 ++++++++++++ libfprint/drivers/synaptics/src/synaptics.c | 665 ++++++++++++ .../synaptics/src/transport/transport.c | 144 +++ .../synaptics/src/transport/usb_transport.c | 453 ++++++++ libfprint/drivers/synaptics/src/util.c | 136 +++ libfprint/meson.build | 34 + meson.build | 4 +- 34 files changed, 5720 insertions(+), 2 deletions(-) create mode 100644 libfprint/drivers/synaptics/include/bmkt.h create mode 100644 libfprint/drivers/synaptics/include/bmkt_internal.h create mode 100644 libfprint/drivers/synaptics/include/bmkt_message.h create mode 100644 libfprint/drivers/synaptics/include/bmkt_response.h create mode 100644 libfprint/drivers/synaptics/include/crc.h create mode 100644 libfprint/drivers/synaptics/include/event.h create mode 100644 libfprint/drivers/synaptics/include/mutex.h create mode 100644 libfprint/drivers/synaptics/include/platform/linux/platform.h create mode 100644 libfprint/drivers/synaptics/include/platform/posix/plat_thread.h create mode 100644 libfprint/drivers/synaptics/include/platform/posix/posix.h create mode 100644 libfprint/drivers/synaptics/include/sensor.h create mode 100644 libfprint/drivers/synaptics/include/synaptics.h create mode 100644 libfprint/drivers/synaptics/include/thread.h create mode 100644 libfprint/drivers/synaptics/include/transport/transport.h create mode 100644 libfprint/drivers/synaptics/include/transport/usb_transport.h create mode 100644 libfprint/drivers/synaptics/src/auth.c create mode 100644 libfprint/drivers/synaptics/src/bmkt.c create mode 100644 libfprint/drivers/synaptics/src/bmkt_message.c create mode 100644 libfprint/drivers/synaptics/src/crc.c create mode 100644 libfprint/drivers/synaptics/src/enroll.c create mode 100644 libfprint/drivers/synaptics/src/platform/linux/plat_event.c create mode 100644 libfprint/drivers/synaptics/src/platform/linux/plat_log.c create mode 100644 libfprint/drivers/synaptics/src/platform/posix/plat_mutex.c create mode 100644 libfprint/drivers/synaptics/src/platform/posix/plat_thread.c create mode 100644 libfprint/drivers/synaptics/src/platform/posix/posix.c create mode 100644 libfprint/drivers/synaptics/src/sensor.c create mode 100644 libfprint/drivers/synaptics/src/synaptics.c create mode 100644 libfprint/drivers/synaptics/src/transport/transport.c create mode 100644 libfprint/drivers/synaptics/src/transport/usb_transport.c create mode 100644 libfprint/drivers/synaptics/src/util.c diff --git a/doc/meson.build b/doc/meson.build index 37d515d..49fa233 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -27,6 +27,7 @@ private_headers = [ 'vfs301_proto_fragments.h', 'vfs301_proto.h', 'vfs5011_proto.h', + 'synaptics.h', # NBIS 'morph.h', diff --git a/libfprint/drivers/driver_ids.h b/libfprint/drivers/driver_ids.h index 8839a74..c6b9247 100644 --- a/libfprint/drivers/driver_ids.h +++ b/libfprint/drivers/driver_ids.h @@ -42,6 +42,7 @@ enum { VFS5011_ID = 19, VFS0050_ID = 20, ELAN_ID = 21, + SYNAPTICS_ID = 22, }; #endif diff --git a/libfprint/drivers/synaptics/include/bmkt.h b/libfprint/drivers/synaptics/include/bmkt.h new file mode 100644 index 0000000..c25124b --- /dev/null +++ b/libfprint/drivers/synaptics/include/bmkt.h @@ -0,0 +1,981 @@ +/* + * Synaptics MiS Fingerprint Sensor Interface + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef _BMKT_H_ +#define _BMKT_H_ + +/**< User ID maximum length allowed */ +#define BMKT_MAX_USER_ID_LEN 100 +/**< Software Part Number length */ +#define BMKT_PART_NUM_LEN 10 +/**< Software supplier identification length */ +#define BMKT_SUPPLIER_ID_LEN 2 + +/**< Maximum namber of templates for storing in internal flash of the fingerprint sensor */ +#define BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH 15 + +#include +#include "bmkt_response.h" + +/*! +******************************************************************************* +** Type definition for result +*/ +/** No error; Operation successfully completed. */ +#define BMKT_SUCCESS 0 +/** Fingerprint system not initialized */ +#define BMKT_FP_SYSTEM_NOT_INITIALIZED 101 +/** Fingerprint system busy performing another operation */ +#define BMKT_FP_SYSTEM_BUSY 102 +/** Operation not allowed */ +#define BMKT_OPERATION_DENIED 103 +/** System ran out of memory while performing operation */ +#define BMKT_OUT_OF_MEMORY 104 +/** Corrupt message, CRC check fail or truncated message */ +#define BMKT_CORRUPT_MESSAGE 110 +/** One of the command parameters is outside the range of valid values */ +#define BMKT_INVALID_PARAM 111 +/** Unrecognized message or message with invalid message ID */ +#define BMKT_UNRECOGNIZED_MESSAGE 112 +/** Operation time out */ +#define BMKT_OP_TIME_OUT 113 +/** General error – cause of error cannot be determined */ +#define BMKT_GENERAL_ERROR 114 + +#define BMKT_SET_SECURITY_LEVEL_FAIL 120 +#define BMKT_GET_SECURITY_LEVEL_FAIL 121 + +/** Fingerprint sensor reset while operation was being performed */ +#define BMKT_SENSOR_RESET 201 +/** Fingerprint sensor malfunctioned */ +#define BMKT_SENSOR_MALFUNCTION 202 +/** Fingerprint sensor cannot be accessed despite repeated attempts */ +#define BMKT_SENSOR_TAMPERED 203 +/** +* BMKT_SENSOR_NOT_INIT: +* Fingerprint sensor module not initialized yet – not ready for use +* (different from error code 101 which indicates that the entire system +* has not been initialized) +*/ +#define BMKT_SENSOR_NOT_INIT 204 +/** Number of re-pairing operations exceeded limit or re-pairing has been disabled */ +#define BMKT_OWNERSHIP_RESET_MAX_EXCEEDED 205 +/** +* BMKT_SENSOR_STIMULUS_ERROR: +* There is a finger or debris on the sensor that needs to be removed +* before issuing this command +*/ +#define BMKT_SENSOR_STIMULUS_ERROR 213 +/** +* BMKT_CORRUPT_TEMPLATE_DATA: +* One of the fingerprint templates stored on flash is corrupt. +* This error code is returned in case of failure in finding a fingerprint match +* during identify or verify operations while also detecting that one or more +* fingerprint templates stored on the flash has become corrupted +*/ +#define BMKT_CORRUPT_TEMPLATE_DATA 300 +/** Failed to extract features from fingerprint image acquired by sensor */ +#define BMKT_FEATURE_EXTRACT_FAIL 301 +/** Failed to generate fingerprint template */ +#define BMKT_ENROLL_FAIL 302 +/** Specified finger already enrolled for this user */ +#define BMKT_ENROLLMENT_EXISTS 303 +/** Invalid fingerprint image */ +#define BMKT_INVALID_FP_IMAGE 304 +/** No matching user fingerprint template found in database */ +#define BMKT_FP_NO_MATCH 404 +/** Fingerprint database is full */ +#define BMKT_FP_DATABASE_FULL 501 +/** Fingerprint database is empty */ +#define BMKT_FP_DATABASE_EMPTY 502 +/** Cannot access fingerprint database */ +#define BMKT_FP_DATABASE_ACCESS_FAIL 503 +/** Fingerprint template record does not exist */ +#define BMKT_FP_DATABASE_NO_RECORD_EXISTS 504 +/** Failed to read/write system parameters stored on flash */ +#define BMKT_FP_PARAM_ACCESS_FAIL 505 +/** Fingerprint is a spoof */ +#define BMKT_FP_SPOOF_ALERT 801 +/** Anti-spoof module failure */ +#define BMKT_ANTI_SPOOF_MODULE_FAIL 802 + +#define BMKT_CORRUPT_UPDATE_IMAGE 901 +#define BMKT_SYSTEM_UPDATE_FAIL 902 + +#define BMKT_EVENT_NOT_SET 1000 +#define BMKT_SENSOR_NOT_READY 1001 +#define BMKT_TIMEOUT 1002 +#define BMKT_SENSOR_RESPONSE_PENDING 1003 + +#define BMKT_SENSOR_FLAGS_POLLING 0x1 + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* bmkt_mode: +* Fingerprint system operational mode values level 1 +*/ +typedef enum bmkt_mode +{ + BMKT_STATE_UNINIT = 0xFF, + BMKT_STATE_IDLE = 0x00, + BMKT_STATE_ENROLL = 0x10, + BMKT_STATE_IDENTIFY = 0x20, + BMKT_STATE_VERIFY = 0x30, + BMKT_STATE_DB_OPS = 0x40, + BMKT_STATE_SYS_TEST = 0x50, + BMKT_STATE_SYS_OPS = 0x60, +} bmkt_mode_t; + +/** +* bmkt_mode_level2: +* Fingerprint system operational mode values level 2 +*/ +typedef enum bmkt_mode_level2 +{ + BMKT_STATE_L2_IDLE = 0x00, + BMKT_STATE_L2_STARTING = 0x11, + BMKT_STATE_L2_WAITING_FOR_FINGER = 0x12, + BMKT_STATE_L2_CAPTURE_IMAGE = 0x13, + BMKT_STATE_L2_CAPTURE_COMPLETE = 0x14, + BMKT_STATE_L2_EXTRACT_FEATURE = 0x15, + BMKT_STATE_L2_CREATE_TEMPLATE = 0x16, + BMKT_STATE_L2_READING_FROM_FLASH = 0x17, + BMKT_STATE_L2_WRITING_TO_FLASH = 0x18, + BMKT_STATE_L2_FINISHING = 0x19, + BMKT_STATE_L2_CANCELING_OP = 0x20, + BMKT_STATE_L2_MATCHING = 0x21, + BMKT_STATE_L2_TRANSMITTING_RESPONSE = 0x22, + BMKT_STATE_L2_READY_POWER_DOWN = 0xF0, +} bmkt_mode_level2_t; + +/** +* bmkt_transport_type: +* Fingerprint system transport types +*/ +typedef enum bmkt_transport_type +{ + BMKT_TRANSPORT_TYPE_USB = 0, +} bmkt_transport_type_t; + +/** +* bmkt_usb_config: +* Structure represcontainingenting USB configuration details +*/ +typedef struct bmkt_usb_config +{ + int product_id; /**< USB device product ID */ +} bmkt_usb_config_t; + +/** +* bmkt_transport_config_t: +* Union containing transport configuration details +*/ +typedef union +{ + bmkt_usb_config_t usb_config; +} bmkt_transport_config_t; + +/** +* bmkt_sensor_desc_t: +* Structure containing fingerprint system description +*/ +typedef struct bmkt_sensor_desc +{ + bmkt_transport_type_t xport_type; /**< Transport type */ + bmkt_transport_config_t xport_config; /**< Transport configuration */ + int flags; +} bmkt_sensor_desc_t; + +/** +* bmkt_finger_state_t: +* Finger state representation values. +*/ +typedef enum +{ + BMKT_FINGER_STATE_UNKNOWN = 0, + BMKT_FINGER_STATE_ON_SENSOR, + BMKT_FINGER_STATE_NOT_ON_SENSOR, +} bmkt_finger_state_t; + +/** +* bmkt_finger_event_t: +* Structure containing finger state +*/ +typedef struct bmkt_finger_event +{ + bmkt_finger_state_t finger_state; +} bmkt_finger_event_t; + +typedef struct bmkt_user_id +{ + uint8_t user_id_len; + uint8_t user_id[BMKT_MAX_USER_ID_LEN]; +} bmkt_user_id_t; + +typedef struct bmkt_ctx bmkt_ctx_t; +typedef struct bmkt_sensor bmkt_sensor_t; +typedef struct bmkt_sensor_desc bmkt_sensor_desc_t; +typedef struct bmkt_event bmkt_event_t; + +typedef int (*bmkt_resp_cb_t)(bmkt_response_t *resp, void *cb_ctx); +typedef int (*bmkt_event_cb_t)(bmkt_finger_event_t *event, void *cb_ctx); +typedef int (*bmkt_general_error_cb_t)(uint16_t error, void *cb_ctx); + +/** +* bmkt_init: +* @brief Initialize the bmkt library. +* +* @param[out] ctx A double pointer to return the created library module context pointer. +* +* @return BMKT_SUCCESS +* BMKT_INVALID_PARAM +* +* The bmkt_init function must be invoked to intialize the bmkt library before calling other functions. +* The library module context pointer is returned, which must be passed to all other library interface functions. +*/ +int +bmkt_init( + bmkt_ctx_t ** ctx); + +/** +* bmkt_exit: +* @brief Uninitialize the bmkt library. +* +* @param[in] ctx Context pointer created by bmkt_init. +* +* @return none +* +* The bmkt_exit function must be invoked when the module is no longer needed. +*/ + +void +bmkt_exit( + bmkt_ctx_t * ctx); + +/** +* bmkt_open: +* @brief Open the specified sensor module. +* +* @param[in] ctx Context pointer created by bmkt_init. +* @param[in] desc The specified sensor description. +* @param[out] sensor A double pointer to return the created sensor module pointer +* @param[in] err_cb General Error callback function +* @param[in] err_cb_ctx General Error callback user context +* +* @return VCS_RESULT_OK if success +* +* The bmkt_open function must be called to open a specific sensor module. Returned sensor module pointer +* must be passed to all other interface functions that expect a sensor pointer. +*/ + +int +bmkt_open( + bmkt_ctx_t * ctx, + const bmkt_sensor_desc_t * desc, + bmkt_sensor_t ** sensor, + bmkt_general_error_cb_t err_cb, + void * err_cb_ctx); + +/** +* bmkt_close: +* @brief Close the specified sensor module, and release all the resources +* +* @param[in] sensor The sensor module pointer +* +* @return VCS_RESULT_OK if success +* +* The bmkt_close function must be invoked when the sensor module is no longer needed. +*/ +int +bmkt_close( + bmkt_sensor_t * sensor); + +/** +* bmkt_init_fps: +* @brief Initialize the sensor module. +* +* @param[in] sensor The sensor module pointer +* +* @return VCS_RESULT_OK if success +* +* Initializes the fingerprint sensor module. Must be the first command to be issued to the fingerprint sensor module, before any other commands are issued. +*/ +int +bmkt_init_fps( + bmkt_sensor_t * sensor); + +/** +* bmkt_enroll: +* @brief Put the fingerprint sensor module into enrollment mode to Enroll a user’s fingerprint into the system. +* +* @param[in] sensor The sensor module pointer +* @param[in] user_id Enrolled User ID +* @param[in] user_id_len Enrolled User ID lenght +* @param[in] finger_id Enrolled finger ID +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_ENROLL_READY +* - BMKT_RSP_CAPTURE_COMPLETE +* - BMKT_RSP_ENROLL_REPORT +* - BMKT_RSP_ENROLL_PAUSED +* - BMKT_RSP_ENROLL_RESUMED +* - BMKT_RSP_ENROLL_FAIL +* - BMKT_RSP_ENROLL_OK + +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* Enrolled users have to touch the fingerprint sensor multiple times based on cues provided by the system. +* After successful enrollment, a template is generated from features of the user’s fingerprint and stored +* in encrypted storage within the fingerprint sensor module. +* When this command is being executed, fingerprint sensor module’s mode is: Enrollment +*/ +int +bmkt_enroll( + bmkt_sensor_t * sensor, + const uint8_t * user_id, + uint32_t user_id_len, + uint8_t finger_id, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_enroll_pause: +* @brief Pause enrollment operation. +* +* @param[in] sensor The sensor module pointer +* +* @return VCS_RESULT_OK if success +* +* Enroll pause operation is applicable if fingerprint sensor is in Enrollment mode. +*/ +int +bmkt_enroll_pause( + bmkt_sensor_t * sensor); + +/** +* bmkt_enroll_resume: +* @brief Resume enrollment operation. +* +* @param[in] sensor The sensor module pointer +* +* @return VCS_RESULT_OK if success +* +* Enroll resume operation is applicable if fingerprint sensor enrollment is paused. +* Otherwise it has no effect. +*/ +int +bmkt_enroll_resume( + bmkt_sensor_t * sensor); + +/** +* bmkt_identify: +* @brief Put the fingerprint sensor module into identification mode. +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function.Available responses: +* - BMKT_RSP_CAPTURE_COMPLETE +* - BMKT_RSP_ID_READY +* - BMKT_RSP_ID_FAIL +* - BMKT_RSP_ID_OK +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* The user being identified has to touch the fingerprint sensor once based on a cue provided by the system. +* If a user cannot be identified based on the stored templates of enrolled users or if the fingerprint sensor +* module detects that the fingerprint being presented to the sensor is a spoof, then an error response is generated. +* The order of matching is such that the enrolled template with the most recent successful match is matched against +* first and then the remaining templates are matched in the order of storage. +* When this command is being executed, fingerprint sensor module’s mode is: Identification +*/ +int +bmkt_identify( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_verify: +* @brief Put the fingerprint sensor module into verification mode. +* +* @param[in] sensor The sensor module pointer +* @param[in] user Enrolled User +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_CAPTURE_COMPLETE +* - BMKT_RSP_VERIFY_READY +* - BMKT_RSP_VERIFY_FAIL +* - BMKT_RSP_VERIFY_OK +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* The user being verifyed has to touch the fingerprint sensor once based on a cue provided by the system. +* The Captured fingerprint is matched only against the stored templates corresponding to specifyed user ID, +* If a user’s fingerprint cannot be matched to any of the stored fingerprint templates of the specified user or +* if the fingerprint sensor module detects that the fingerprint being presented to the sensor is a spoof, +* then an error response is generated. +* When this command is being executed, fingerprint sensor module’s mode is: Verification +*/ +int +bmkt_verify( + bmkt_sensor_t * sensor, + bmkt_user_id_t* user, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_get_security_level: +* @brief Get security level of the fingerprint sensor module. +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_GET_SECURITY_LEVEL_REPORT +* - BMKT_RSP_GET_SECURITY_LEVEL_FAIL +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* Security levels affects the False Accept Rate(FAR) and the corresponding False Reject Rate(FRR). +* The higher the security level, the lower the FAR and higher the FRR. +* When this command is being executed, fingerprint sensor module’s mode is: Miscellaneous system operations +*/ +int +bmkt_get_security_level( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_set_security_level: +* @brief Set security level of the fingerprint sensor module. +* +* @param[in] sensor The sensor module pointer +* @param[in] level The security level to be set +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_SET_SECURITY_LEVEL_REPORT +* - BMKT_RSP_SET_SECURITY_LEVEL_FAIL +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* Security levels affects the False Accept Rate(FAR) and the corresponding False Reject Rate(FRR). +* The higher the security level, the lower the FAR and higher the FRR. +* When this command is being executed, fingerprint sensor module’s mode is: Miscellaneous system operations +*/ +int +bmkt_set_security_level( + bmkt_sensor_t * sensor, + bmkt_sec_level_t level, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_get_version: +* @brief Get system version information from the fingerprint sensor module. +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_VERSION_INFO +* - BMKT_RSP_GET_VERSION_FAIL +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* When this command is being executed, fingerprint sensor module’s mode is: Miscellaneous system operations +*/ +int +bmkt_get_version( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_get_enrolled_users: +* @brief Get list of enrolled fingerprint template records from the template database. +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_TEMPLATE_RECORDS_REPORT +* - BMKT_RSP_QUERY_RESPONSE_COMPLETE +* - BMKT_RSP_QUERY_FAIL +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* The total length of a single response message is limited to 255 bytes hence, depending on how many enrolled fingerprint templates are present in the template database, +* it may be necessary to split the list of template records of enrolled fingers into multiple messages. +* The bmkt_get_next_enrolled_users function should be called sequentially until one of conditions are met: +* - Responce is obtained with BMKT_RSP_QUERY_RESPONSE_COMPLETE response id. +* - The response's "query_sequence" field value is equal to "total_query_messages" value. +* When this command is being executed, fingerprint sensor module’s mode is: Database operations +*/ +int +bmkt_get_enrolled_users( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_get_next_enrolled_users: +* @brief Continue to get list of enrolled fingerprint template records from the template database. +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_TEMPLATE_RECORDS_REPORT +* - BMKT_RSP_QUERY_RESPONSE_COMPLETE +* - BMKT_RSP_QUERY_FAIL +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* The total length of a single response message is limited to 255 bytes hence, depending on how many enrolled fingerprint templates are present in the template database, +* it may be necessary to split the list of template records of enrolled fingers into multiple messages. +* The bmkt_get_next_enrolled_users function should be called sequentially until one of conditions are met: +* - Responce is obtained with BMKT_RSP_QUERY_RESPONSE_COMPLETE response id. +* - The response's "query_sequence" field value is equal to "total_query_messages" value. +* When this command is being executed, fingerprint sensor module’s mode is: Database operations +*/ +int +bmkt_get_next_enrolled_users( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_get_enrolled_fingers: +* @brief Get list of enrolled fingers for a specific user from the fingerprint template database. +* +* @param[in] sensor The sensor module pointer +* @param[in] user_id Enrolled User ID +* @param[in] user_id_len Enrolled User ID lenght +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_GET_ENROLLED_FINGERS_REPORT +* - BMKT_RSP_QUERY_FAIL +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* When this command is being executed, fingerprint sensor module’s mode is: Database operations +*/ +int +bmkt_get_enrolled_fingers( + bmkt_sensor_t * sensor, + const char * user_id, + uint32_t user_id_len, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_delete_all_enrolled_users: +* @brief Delete entire fingerprint template database. +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_DELETE_PROGRESS +* - BMKT_RSP_DEL_FULL_DB_FAIL +* - BMKT_RSP_DEL_FULL_DB_OK +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* When this command is being executed, fingerprint sensor module’s mode is: Database operations +*/ +int +bmkt_delete_all_enrolled_users( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_delete_enrolled_user: +* @brief Delete a specific fingerprint template of an enrolled user from the database. +* +* @param[in] sensor The sensor module pointer +* @param[in] finger_id Finger ID to be deleted +* @param[in] user_id User ID to be deleted +* @param[in] user_id_len User ID lenght +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_DEL_USER_FP_FAIL +* - BMKT_RSP_DEL_USER_FP_OK +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* If the value of finger ID is set equal to 0 then all fingerprints of that user will be deleted from the database. +* If the value of user ID is set to an empty string (string with length 0) and the finger ID is set equal to 0 then +* all templates stored in the fingerprint database which are marked as corrupt will be deleted. +* When this command is being executed, fingerprint sensor module’s mode is: Database operations +*/ +int +bmkt_delete_enrolled_user( + bmkt_sensor_t * sensor, + uint8_t finger_id, + const char * user_id, + uint32_t user_id_len, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_db_capacity: +* @brief Get information about storage capacity of fingerprint template database. +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_QUERY_FAIL +* - BMKT_RSP_DATABASE_CAPACITY_REPORT +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* When this command is executed, the fingerprint sensor module also checks the fingerprint template database for corrupt records +* When this command is being executed, fingerprint sensor module’s mode is: Database operations +*/ +int +bmkt_db_capacity( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_get_fps_mode: +* @brief Get current operational mode of the fingerprint sensor module. +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_FPS_MODE_FAIL +* - BMKT_RSP_FPS_MODE_REPORT +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* When this command is being executed, it has no effect on the mode on the fingerprint sensor module. +*/ +int +bmkt_get_fps_mode( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_cancel_op: +* @brief Cancelling the current operation and returning the fingerprint sensor module to idle mode. +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_CANCEL_OP_FAIL +* - BMKT_RSP_CANCEL_OP_OK +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* After initialization, the fingerprint sensor module can return to idle mode in only one of two ways : +* (1) due to completion of current operation; +* (2) due to cancellation of current operation. +* When this command is being executed, fingerprint sensor module’s mode is: Miscellaneous system operations +*/ +int +bmkt_cancel_op( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_register_finger_event_notification: +* @brief Register finger presence event callback function +* +* @param[in] sensor The sensor module pointer +* @param[in] cb Event callback function +* @param[in] cb_ctx Event callback user context +* +* @return VCS_RESULT_OK if success +* +* The registered callback function will be called whenever a finger is detected as being placed on the sensor or removed from the sensor. +*/ +int +bmkt_register_finger_event_notification( + bmkt_sensor_t * sensor, + bmkt_event_cb_t cb, + void * cb_ctx); + +/** +* bmkt_notify_shutdown: +* @brief Notify the fingerprint sensor module that a power shutdown is imminent. +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_POWER_DOWN_READY +* - BMKT_RSP_POWER_DOWN_FAIL +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* This will enable the fingerprint sensor module to complete all pending tasks such as writes to the flash memory and respond back to the +* caller when it is ready to be powered down. +* When this command is being executed, fingerprint sensor module’s mode is: Miscellaneous system operations +*/ +int +bmkt_notify_shutdown( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_get_status: +* @brief Get Status of the fingerprint sensor module (is it functioning properly or not). +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_SENSOR_STATUS_REPORT +* - BMKT_RSP_SENSOR_STATUS_FAIL +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* When this command is being executed, fingerprint sensor module’s mode is: Miscellaneous system operations +*/ +int +bmkt_get_status( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_repeat_last_responce: +* @brief Repeat last responce sent +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL +* - The last responce transmitted by FPS module +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* The fingerprint sensor module will respond to this command by simply re - sending its last response without +* making any modifications to the original response message whatsoever. +*/ +int +bmkt_repeat_last_responce( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_get_final_result: +* @brief Retrive final result +* +* @param[in] sensor The sensor module pointer +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL +* - The final result of last opeartion. +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* The fingerprint sensor module will respond to this command by simply re - sending its last response without +* making any modifications to the original response message whatsoever. +* The fingerprint sensor module will respond to this command by simple re - sending response message +* containing the final result returned by the last command executed, as long as the command is one of these: +* -Enroll user +* -Identify user +* -Verify user +* -Delete user fingerprint +* -Delete full database +* -Identify user in order +* -Verify user in order +* -Verify finger in order +*/ +int +bmkt_get_final_result( + bmkt_sensor_t * sensor, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_identify_in_order: +* @brief Put the fingerprint sensor module into identification mode for matching in pre - defined order. +* +* @param[in] sensor The sensor module pointer +* @param[in] user_num_total The total number of user IDs in priority list +* @param[in] user_num_in_order_list The number of user IDs in this function call +* @param[in] order_list Pointer to first user ID record followed by next entries. +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_SEND_NEXT_USER_ID - Notify caller to send the next batch of user IDs in the priority list. +* - BMKT_RSP_CAPTURE_COMPLETE +* - BMKT_RSP_ID_READY +* - BMKT_RSP_ID_FAIL +* - BMKT_RSP_ID_OK +* @param[in] cb_ctx responce callback user context +* +* @return VCS_RESULT_OK if success +* +* Do identification operation with specified priority list of user IDs for matching, starting with the highest priority and ending with the lowest priority. +* The system continues matching against enrolled templates in the order specified till there is a successful match or till the entire template database has +* been scanned and matched against. +* If the entire priority list of user IDs fits within the payload of this command then the fingerprint sensor module will not respond with a +* BMKT_RSP_SEND_NEXT_USER_ID and instead will respond directly with BMKT_RSP_ID_READY +* When this command is being executed, fingerprint sensor module’s mode is: Identification +*/ +int +bmkt_identify_in_order( + bmkt_sensor_t * sensor, + uint32_t user_num_total, + uint32_t user_num_in_order_list, + bmkt_user_id_t * order_list, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_identify_in_order_next_users: +* @brief Send next batch of user IDs to fingerprint sensor module for identify if a BMKT_RSP_SEND_NEXT_USER_ID response is received. +* +* @param[in] sensor The sensor module pointer +* @param[in] user_num_in_order_list The number of user IDs in this function call +* @param[in] order_list Pointer to first user ID record followed by next entries. +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_SEND_NEXT_USER_ID - Notify caller to send the next batch of user IDs in the priority list. +* - BMKT_RSP_CAPTURE_COMPLETE +* - BMKT_RSP_ID_READY +* - BMKT_RSP_ID_FAIL +* - BMKT_RSP_ID_OK +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* If caller receives a BMKT_RSP_SEND_NEXT_USER_ID response from the fingerprint sensor module but there are no more user IDs to be sent, +* it must set the payload length of this command to 0 in order to indicate end of list. +* When this command is being executed, fingerprint sensor module’s mode is: Identification +*/ +int +bmkt_identify_in_order_next_users( + bmkt_sensor_t * sensor, + uint32_t user_num_in_order_list, + bmkt_user_id_t * order_list, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_verify_in_order: +* @brief Put the fingerprint sensor module into verifying mode for matching against enrolled templates of multiple users, as specified by the priority list +* +* @param[in] sensor The sensor module pointer +* @param[in] user_num_total The total number of user IDs in priority list +* @param[in] user_num_in_order_list The number of user IDs in this function call +* @param[in] order_list Pointer to first user ID record followed by next entries. +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_CAPTURE_COMPLETE +* - BMKT_RSP_SEND_NEXT_USER_ID - Notify caller to send the next batch of user IDs in the priority list. +* - BMKT_RSP_VERIFY_READY +* - BMKT_RSP_VERIFY_FAIL +* - BMKT_RSP_VERIFY_OK +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* Do verification operation with specified priority list of user IDs for matching, starting with the highest priority and ending with the lowest priority. +* The system continues matching against enrolled templates in the order specified till there is a successful match or till the entire template database has +* been scanned and matched against. +* If the entire priority list of user IDs fits within the payload of this command then the fingerprint sensor module will not respond with a +* BMKT_RSP_SEND_NEXT_USER_ID and instead will respond directly with BMKT_RSP_ID_READY +* When this command is being executed, fingerprint sensor module’s mode is: Verification +*/ +int +bmkt_verify_in_order( + bmkt_sensor_t * sensor, + uint32_t user_num_total, + uint32_t user_num_in_order_list, + bmkt_user_id_t * order_list, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_verify_in_order_next_users: +* @brief Send next batch of user IDs to fingerprint sensor module for verify if a BMKT_RSP_SEND_NEXT_USER_ID response is received. +* +* @param[in] sensor The sensor module pointer +* @param[in] user_num_in_order_list The number of user IDs in this function call +* @param[in] order_list Pointer to first user ID record followed by next entries. +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_CAPTURE_COMPLETE +* - BMKT_RSP_SEND_NEXT_USER_ID - Notify caller to send the next batch of user IDs in the priority list. +* - BMKT_RSP_ID_READY +* - BMKT_RSP_ID_FAIL +* - BMKT_RSP_ID_OK +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* If caller receives a BMKT_RSP_SEND_NEXT_USER_ID response from the fingerprint sensor module but there are no more user IDs to be sent, +* it must set the payload length of this command to 0 in order to indicate end of list. +* When this command is being executed, fingerprint sensor module’s mode is: Verification +*/ +int +bmkt_verify_in_order_next_users( + bmkt_sensor_t * sensor, + uint32_t user_num_in_order_list, + bmkt_user_id_t * order_list, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +/** +* bmkt_verify_finger_in_order: +* @brief Put the fingerprint sensor module into verifying mode for matching against enrolled finger templates of specific user, as specified by the priority list +* +* @param[in] sensor The sensor module pointer +* @param[in] user_id The user ID +* @param[in] user_id_len The user ID lenght +* @param[in] user_num_in_order_list The number of finger IDs in the order list +* @param[in] order_list Pointer to first finger ID followed by next values. +* @param[in] resp_cb Responce callback function. Available responses: +* - BMKT_RSP_VERIFY_READY +* - BMKT_RSP_CAPTURE_COMPLETE +* - BMKT_RSP_VERIFY_FAIL +* - BMKT_RSP_VERIFY_OK +* @param[in] cb_ctx Responce callback user context +* +* @return VCS_RESULT_OK if success +* +* Verifying the identity of a user by matching against enrolled finger templates in the order specified by the caller till there is a successful match or till the +* entire priority list of fingers has been scanned and matched against.If the priority list of fingers is a proper subset of the set of fingers enrolled for that user, +* then the remaining fingers are matched in the order of storage.In case there is a finger ID specified in the priority list which does not exist for that user ID in the +* fingerprint template database, then the system will terminate the operation and return error code 504. +*/ +int +bmkt_verify_finger_in_order( + bmkt_sensor_t * sensor, + const uint8_t * user_id, + uint32_t user_id_len, + uint32_t finger_num_in_order_list, + uint8_t * order_list, + bmkt_resp_cb_t resp_cb, + void * cb_ctx); + +int +bmkt_process_pending_interrupts( + bmkt_sensor_t * sensor); + +#ifdef __cplusplus +} +#endif + +#endif /* _BMKT_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/bmkt_internal.h b/libfprint/drivers/synaptics/include/bmkt_internal.h new file mode 100644 index 0000000..0852a37 --- /dev/null +++ b/libfprint/drivers/synaptics/include/bmkt_internal.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef _BMKT_INTERNAL_H_ +#define _BMKT_INTERNAL_H_ + +#include "bmkt.h" +#include "bmkt_message.h" +#include "platform.h" + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +typedef enum +{ + BYTE_ORDER_BIG = 0, + BYTE_ORDER_LITTLE = 1, + BYTE_ORDER_SENSOR = BYTE_ORDER_LITTLE, +} bmkt_byte_order_t; + +uint32_t extract32(const uint8_t *buf, int *offset, bmkt_byte_order_t byte_order); +uint16_t extract16(const uint8_t *buf, int *offset, bmkt_byte_order_t byte_order); +uint8_t extract8(const uint8_t *buf, int *offset, bmkt_byte_order_t byte_order); + +void encode32(uint32_t value, uint8_t *buf, int *offset, bmkt_byte_order_t byte_order); +void encode16(uint16_t value, uint8_t *buf, int *offset, bmkt_byte_order_t byte_order); +void encode8(uint8_t value, uint8_t *buf, int *offset, bmkt_byte_order_t byte_order); + +#ifdef FULL_LOGGING +void print_buffer(uint8_t *buf, int len); +#endif + +#endif /* _BMKT_INTERNAL_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/bmkt_message.h b/libfprint/drivers/synaptics/include/bmkt_message.h new file mode 100644 index 0000000..affebd6 --- /dev/null +++ b/libfprint/drivers/synaptics/include/bmkt_message.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + + +#ifndef BMKT_MESSAGE_H_ +#define BMKT_MESSAGE_H_ + +#include "bmkt_internal.h" + +#define BMKT_MESSAGE_HEADER_ID 0xFE +#define BMKT_MESSAGE_HEADER_LEN (4) +#define BMKT_MESSAGE_CRC32_LEN (4) +#define BMKT_MESSAGE_HEADER_ID_FIELD 0 +#define BMKT_MESSAGE_SEQ_NUM_FIELD 1 +#define BMKT_MESSAGE_ID_FIELD 2 +#define BMKT_MESSAGE_PAYLOAD_LEN_FIELD 3 +#define BMKT_MESSAGE_PAYLOAD_FIELD 4 + +// Command messages +#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE 0x01 +#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE_STOP 0x04 +#define BMKT_CMD_SENSOR_MODULE_TEST 0x06 +#define BMKT_CMD_SENSOR_MODULE_TEST_START 0x08 +#define BMKT_CMD_NEXT_TEST_REPORT_CHUNK 0x0B +#define BMKT_CMD_FPS_INIT 0x11 +#define BMKT_CMD_GET_FPS_MODE 0x21 +#define BMKT_CMD_SET_SECURITY_LEVEL 0x31 +#define BMKT_CMD_GET_SECURITY_LEVEL 0x34 +#define BMKT_CMD_CANCEL_OP 0x41 +#define BMKT_CMD_ENROLL_USER 0x51 +#define BMKT_CMD_ENROLL_PAUSE 0x52 +#define BMKT_CMD_ENROLL_RESUME 0x53 +#define BMKT_CMD_ID_USER 0x61 +#define BMKT_CMD_VERIFY_USER 0x65 +#define BMKT_CMD_GET_TEMPLATE_RECORDS 0x71 +#define BMKT_CMD_GET_NEXT_QUERY_RESPONSE 0x72 +#define BMKT_CMD_GET_ENROLLED_FINGERS 0x73 +#define BMKT_CMD_GET_DATABASE_CAPACITY 0x74 +#define BMKT_CMD_DEL_USER_FP 0x81 +#define BMKT_CMD_DEL_FULL_DB 0x84 +#define BMKT_CMD_REPEAT_LAST_RSP 0x92 +#define BMKT_CMD_POWER_DOWN_NOTIFY 0xA1 +#define BMKT_CMD_GET_VERSION 0xB1 +#define BMKT_CMD_DISABLE_PAIRING 0xC2 +#define BMKT_CMD_QUERY_PAIRING 0xC5 +#define BMKT_CMD_SENSOR_STATUS 0xD1 +#define BMKT_CMD_ID_USER_IN_ORDER 0xE1 +#define BMKT_CMD_ID_NEXT_USER 0xE3 +#define BMKT_CMD_VERIFY_USER_IN_ORDER 0xF1 +#define BMKT_CMD_VERIFY_FINGERS_IN_ORDER 0xF2 +#define BMKT_CMD_GET_FINAL_RESULT 0xE4 + +#define BMKT_EVT_FINGER_REPORT 0x91 + +#define BMKT_EVT_FINGER_STATE_NOT_ON_SENSOR 0x00 +#define BMKT_EVT_FINGER_STATE_ON_SENSOR 0x01 + +typedef struct bmkt_msg_resp +{ + uint8_t msg_id; + uint8_t seq_num; + uint8_t payload_len; + uint8_t *payload; + int result; +} bmkt_msg_resp_t; + +typedef struct bmkt_session_ctx +{ + uint8_t seq_num; + bmkt_resp_cb_t resp_cb; + void *cb_ctx; +} bmkt_session_ctx_t; + +int bmkt_compose_message(uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num, + uint8_t payload_size, uint8_t *payload); + +int bmkt_parse_message_header(uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp); +int bmkt_parse_message_payload(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp); +#endif /* BMKT_MESSAGE_H_ */ diff --git a/libfprint/drivers/synaptics/include/bmkt_response.h b/libfprint/drivers/synaptics/include/bmkt_response.h new file mode 100644 index 0000000..67f5698 --- /dev/null +++ b/libfprint/drivers/synaptics/include/bmkt_response.h @@ -0,0 +1,478 @@ +/* + * Synaptics MiS Fingerprint Sensor Response Data Interface + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + + +#ifndef _BMKT_RESPONSE_H_ +#define _BMKT_RESPONSE_H_ + +/** List of response message IDs */ +#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL 0x02 +#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_READY 0x03 +#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_STOPPED 0x05 +#define BMKT_RSP_SENSOR_MODULE_TEST_READY 0x07 +#define BMKT_RSP_SENSOR_MODULE_TEST_FAIL 0x09 +#define BMKT_RSP_SENSOR_MODULE_TEST_REPORT 0x0A +#define BMKT_RSP_NEXT_TEST_REPORT_CHUNK 0x0C + +/*! \addtogroup init +* Response IDs returned by fingerprint initialization operation +* @{ +*/ +/** Failed to initialize fingerprint sensor module */ +#define BMKT_RSP_FPS_INIT_FAIL 0x12 +/** Successfully initialized fingerprint sensor module */ +#define BMKT_RSP_FPS_INIT_OK 0x13 +/*! @} */ + +/*! \addtogroup mode +* Response IDs returned by get fingerprint mode operation +* @{ +*/ +/** Failed to get fingerprint sensor module’s current operational mode */ +#define BMKT_RSP_FPS_MODE_FAIL 0x22 +/** +* BMKT_RSP_FPS_MODE_REPORT: +* Response containing the current operational mode of the fingerprint sensor module +*
Payload data represented in \ref bmkt_fps_mode_resp_t struct +*/ +#define BMKT_RSP_FPS_MODE_REPORT 0x23 +/*! @} */ + +/*! \addtogroup setseclevel +* Response IDs returned by set security level operation +* @{ +*/ +/** Failed to set fingerprint sensor module security level */ +#define BMKT_RSP_SET_SECURITY_LEVEL_FAIL 0x32 +/** +* BMKT_RSP_SET_SECURITY_LEVEL_REPORT: +* Security level of the fingerprint sensor module was set successfully +*
Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct +*/ +#define BMKT_RSP_SET_SECURITY_LEVEL_REPORT 0x33 +/*! @} */ + +/*! \addtogroup getseclevel +* Response IDs returned by get security level operation +* @{ +*/ +/** Failed to get fingerprint sensor module security level */ +#define BMKT_RSP_GET_SECURITY_LEVEL_FAIL 0x35 +/** +* BMKT_RSP_GET_SECURITY_LEVEL_REPORT: +* Returns the current security level of the fingerprint sensor module +*
Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct +*/ +#define BMKT_RSP_GET_SECURITY_LEVEL_REPORT 0x36 +/*! @} */ + +/*! \addtogroup cancelop +* Response IDs returned by cancel_operation operation +* @{ +*/ +/** +* BMKT_RSP_CANCEL_OP_OK: +* Successfully canceled the current operation and returned +* fingerprint sensor module to idle mode +*/ +#define BMKT_RSP_CANCEL_OP_OK 0x42 +/** Failed to cancel the current operation */ +#define BMKT_RSP_CANCEL_OP_FAIL 0x43 +/*! @} */ + +/*! \addtogroup enrollment +* Response IDs returned by enrollment operation +* @{ +*/ +/** +* BMKT_RSP_ENROLL_READY: +* Fingerprint enrollment session has begun and the user can place +* their finger on the sensor +*/ +#define BMKT_RSP_ENROLL_READY 0x54 +/** Progress of the currently on-going fingerprint enrollment session */ +#define BMKT_RSP_ENROLL_REPORT 0x55 +/** Enrollment has been paused */ +#define BMKT_RSP_ENROLL_PAUSED 0x56 +/** Enrollment has been resume */ +#define BMKT_RSP_ENROLL_RESUMED 0x57 +/** The current enrollment session has encountered an error */ +#define BMKT_RSP_ENROLL_FAIL 0x58 +/** +* BMKT_RSP_ENROLL_OK: +* User has been successfully enrolled into the fingerprint sensor module +*
Contains payload data represented in \ref bmkt_enroll_resp_t struct +*/ +#define BMKT_RSP_ENROLL_OK 0x59 + +/** +* BMKT_RSP_CAPTURE_COMPLETE: +* Fingerprint image capture is complete and it is safe for the user +* to lift their finger off the sensor +*/ +#define BMKT_RSP_CAPTURE_COMPLETE 0x60 +/*! @} */ + +/*! \addtogroup identify +* Response IDs returned by identify operation. +* @{ +*/ +/* Fingerprint identification session has begun */ +#define BMKT_RSP_ID_READY 0x62 +/* Identification has failed */ +#define BMKT_RSP_ID_FAIL 0x63 +/** +* BMKT_RSP_ID_OK: +* User has been successfully identified +*
Contains payload data represented in \ref bmkt_auth_resp struct +*/ +#define BMKT_RSP_ID_OK 0x64 +/*! @} */ + +/*! \addtogroup verify +* Response IDs returned by identify operation. +* @{ +*/ +/** Fingerprint verification session has begun */ +#define BMKT_RSP_VERIFY_READY 0x66 +/** Verification has failed */ +#define BMKT_RSP_VERIFY_FAIL 0x67 +/** +* BMKT_RSP_VERIFY_OK: +* User’s identity has been successfully verified +*
Contains payload data represented in \ref bmkt_auth_resp struct +*/ +#define BMKT_RSP_VERIFY_OK 0x68 +/*! @} */ + +/** +* BMKT_RSP_TEMPLATE_RECORDS_REPORT: +* Response ID returned by get enrolled users templates record operation +*
Returns list of template records containing user IDs and corresponding finger IDs +*
Payload data represented in \ref bmkt_enroll_templates_resp_t struct +*/ +#define BMKT_RSP_TEMPLATE_RECORDS_REPORT 0x75 + +/** +* BMKT_RSP_QUERY_RESPONSE_COMPLETE: +* Response ID returned by get next query response operation +*
Complete sequence of messages containing the template records query response has been sent +*/ +#define BMKT_RSP_QUERY_RESPONSE_COMPLETE 0x76 + +/** +* BMKT_RSP_GET_ENROLLED_FINGERS_REPORT: +* Response ID returned by get enrolled fingers operation +*
Returns list of IDs of enrolled fingers for a specific user, +* along with template record status corresponding to each enrolled finger +*
Contains payload data represented in \ref bmkt_enrolled_fingers_resp_t struct +*/ +#define BMKT_RSP_GET_ENROLLED_FINGERS_REPORT 0x77 + +/*! \addtogroup dbcapacity +* Response IDs returned by get database capacity operation +* @{ +*/ +/** +* BMKT_RSP_DATABASE_CAPACITY_REPORT: +* Response specifying total capacity of fingerprint template database and +* how much free capacity is remaining along with how many templates are corrupted and +* how many bad (permanently unusable) storage slots are there. +*
Payload data represented in \ref bmkt_get_db_capacity_resp_t struct +*/ +#define BMKT_RSP_DATABASE_CAPACITY_REPORT 0x78 +/** Failed to execute database query */ +#define BMKT_RSP_QUERY_FAIL 0x79 +/*! @} */ + +/*! \addtogroup deluser +* Response IDs returned by delete fingerprint of specific user operation +* @{ +*/ +/** Failed to delete a user’s fingerprint template from the database */ +#define BMKT_RSP_DEL_USER_FP_FAIL 0x82 +/** +* BMKT_RSP_DEL_USER_FP_OK: +* Fingerprint template successfully deleted from the database. +* Returns the user ID and finger ID deleted. If value of finger ID is set equal to 0, +* then all fingerprint templates for that user have been deleted from the database +*
Payload data represented in \ref bmkt_del_user_resp_t struct +*/ +#define BMKT_RSP_DEL_USER_FP_OK 0x83 +/*! @} */ + +/*! \addtogroup delfulldb +* Response IDs returned by delete entire fingerprint template DB operation +* @{ +*/ +/** Failed to erase entire fingerprint template database */ +#define BMKT_RSP_DEL_FULL_DB_FAIL 0x85 +/** Successfully erased entire fingerprint template database */ +#define BMKT_RSP_DEL_FULL_DB_OK 0x86 +/** +* BMKT_RSP_DELETE_PROGRESS: +* Notify progress made during the on-going deletion of the full template database +*
Payload data represented in \ref bmkt_del_all_users_resp_t struct +*/ +#define BMKT_RSP_DELETE_PROGRESS 0x87 +/*! @} */ + +/** +* BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL: +* Response ID returned by repeate last response operation +*
Failed to retrieve and re-send last response +*/ +#define BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL 0x93 + +/*! \addtogroup pwrdwn +* Response IDs returned by power down notify operation +* @{ +*/ +/** Fingerprint sensor module is ready to be powered down */ +#define BMKT_RSP_POWER_DOWN_READY 0xA2 +/** Failed to go into power down mode */ +#define BMKT_RSP_POWER_DOWN_FAIL 0xA3 +/*! @} */ + +/*! \addtogroup versioninfo +* Response IDs returned by get version operation +* @{ +*/ +/** +* BMKT_RSP_VERSION_INFO: +* System version information of the fingerprint sensor module +*
Payload data represented in \ref bmkt_get_version_resp_t struct +*/ +#define BMKT_RSP_VERSION_INFO 0xB2 +/* Failed to retrieve and send last response */ +#define BMKT_RSP_GET_VERSION_FAIL 0xB3 +/*! @} */ + +/** +* BMKT_RSP_GENERAL_ERROR: +* Not tied to a specific command-response session. +*
Could be caused by corrupt or truncated command message +*/ +#define BMKT_RSP_GENERAL_ERROR 0xC1 +#define BMKT_RSP_DISABLE_PAIRING_FAIL 0xC3 +#define BMKT_RSP_DISABLE_PAIRING_OK 0xC4 +#define BMKT_RSP_QUERY_PAIRING_FAIL 0xC6 +#define BMKT_RSP_SENSOR_PAIRING_REPORT 0xC7 + +/*! \addtogroup versioninfo +* Response IDs returned by get sensor module status operation +* @{ +*/ +/** +* BMKT_RSP_SENSOR_STATUS_REPORT: +* Response returning the current status of the sensor module +*
Payload data represented in bmkt_XXX struct +*/ +#define BMKT_RSP_SENSOR_STATUS_REPORT 0xD2 +/** Failed to retrieve sensor status */ +#define BMKT_RSP_SENSOR_STATUS_FAIL 0xD3 +/*! @} */ + +/** +* BMKT_RSP_SEND_NEXT_USER_ID: +* Response ID returned by identify user in order operation +*
Notify to send the next batch of user IDs in the priority list +*/ +#define BMKT_RSP_SEND_NEXT_USER_ID 0xE2 +/** +* BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL: +* Response IDs returned by retrieve final result operation +*
Failed to retrieve and re-send cached final result +*/ +#define BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL 0xE5 + +/** +* bmkt_enroll_resp: +* Response payload data structure returned by enrollment operation. +*/ +typedef struct bmkt_enroll_resp +{ + int progress; /**< Shows current progress stutus [0-100] */ + uint8_t finger_id; /**< User's finger id [1-10] */ + uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */ +} bmkt_enroll_resp_t; + +/** +* bmkt_auth_resp: +* Response payload data structure returned by identify and verify operations. +*/ +struct bmkt_auth_resp +{ + double match_result; /**< match result returned by matcher */ + uint8_t finger_id; /**< Matched templates's finger id */ + uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< Matched template's user id */ +}; + +typedef struct bmkt_auth_resp bmkt_verify_resp_t; /**< Returned by verify */ +typedef struct bmkt_auth_resp bmkt_identify_resp_t; /**< Returned by identify */ + +/** +* bmkt_fps_mode_resp: +* Response payload data structure returned by get fingerprint mode operation. +*/ +typedef struct bmkt_fps_mode_resp +{ + uint8_t mode; /**< One of the Level I bmkt_mode_t values */ + uint8_t level2_mode; /**< One of the Level II bmkt_mode_level2_t values */ + uint8_t cmd_id; /**< Message ID of command being executed when bmkt_get_fps_mode was called */ + uint8_t finger_presence; /**< Finger presence status value finger on sensor 1 / finger not on sensor 0 */ +} bmkt_fps_mode_resp_t; + +/** +* bmkt_get_version_resp: +* Response payload data structure returned by get version operation. +*/ +typedef struct bmkt_get_version_resp +{ + uint8_t part[BMKT_PART_NUM_LEN]; /**< Software Part Number */ + uint8_t year; /**< Software Version Year */ + uint8_t week; /**< Software Version Week */ + uint8_t patch; /**< Software Version Patch Level */ + uint8_t supplier_id[BMKT_SUPPLIER_ID_LEN]; /**< Software Supplier Identification */ +} bmkt_get_version_resp_t; + +/** +* bmkt_get_db_capacity_resp: +* Response payload data structure returned by get DB capacity operation. +*/ +typedef struct bmkt_get_db_capacity_resp +{ + uint8_t total; /**< Total Available Capacity: Total number of template records that can be stored */ + uint8_t empty; /**< Free Capacity: Number of template records that can still be stored */ + uint8_t bad_slots; /**< Number of bad template storage slots */ + uint8_t corrupt_templates; /**< Number of corrupt templates */ +} bmkt_get_db_capacity_resp_t; + +/** +* bmkt_sec_level: +* Security level values. +*/ +typedef enum bmkt_sec_level +{ + BMKT_SECURITY_LEVEL_LOW = 0x10, + BMKT_SECURITY_LEVEL_MEDIUM = 0x40, + BMKT_SECURITY_LEVEL_HIGH = 0x60, +} bmkt_sec_level_t; + +/** +* bmkt_set_sec_level_resp: +* Response payload data structure returned by get/set security level operations. +*/ +typedef struct bmkt_set_sec_level_resp +{ + bmkt_sec_level_t sec_level; /**< One of the bmkt_sec_level_t values */ +} bmkt_set_sec_level_resp_t; + +/** +* bmkt_del_all_users_resp: +* Response payload data structure returned by delete all enrolled users operation. +*/ +typedef struct bmkt_del_all_users_resp +{ + int progress; /**< Progress indicator as a percentage */ +} bmkt_del_all_users_resp_t; + +/** +* bmkt_del_user_resp: +* Response payload data structure returned by delete enrolled user operation. +*/ +typedef struct bmkt_del_user_resp +{ + int progress; /**< Progress indicator as a percentage */ +} bmkt_del_user_resp_t; + +/** +* bmkt_enroll_template: +* Structure of enrolled users template record data. +*/ +typedef struct bmkt_enroll_template +{ + uint8_t user_id_len; /**< Length of user_id string */ + uint8_t template_status; /**< Template record status */ + uint8_t finger_id; /**< ID of enrolled finger */ + uint8_t user_id[BMKT_MAX_USER_ID_LEN + 1]; /**< Name of the enrolled user */ +} bmkt_enroll_template_t; + +/** +* bmkt_enroll_templates_resp: +* Response payload data structure returned by get enrolled user list operation. +*/ +typedef struct bmkt_enroll_templates_resp +{ + uint8_t total_query_messages; /**< Total query response messages */ + uint8_t query_sequence; /**< Query response sequence number */ + bmkt_enroll_template_t templates[BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH]; /**< Enrolled user template records list */ +} bmkt_enroll_templates_resp_t; + +/** +* bmkt_enrolled_fingers: +* Structure of template record status corresponding to each enrolled finger. +*/ +typedef struct bmkt_enrolled_fingers +{ + uint8_t finger_id; /**< ID of enrolled finger */ + uint8_t template_status; /**< Template record status of finger_id */ +} bmkt_enrolled_fingers_t; + +/** +* bmkt_enrolled_fingers_resp: +* Response payload data structure returned by get enrolled fingers operation. +*/ +typedef struct bmkt_enrolled_fingers_resp +{ + bmkt_enrolled_fingers_t fingers[10]; /**< List of enroled fingers, max number of supported fingers per user is 10 */ +} bmkt_enrolled_fingers_resp_t; + +/** +* bmkt_response_data_t: +* Union combining all response payload data types. +*/ +typedef union { + bmkt_enroll_resp_t enroll_resp; + bmkt_verify_resp_t verify_resp; + bmkt_identify_resp_t id_resp; + bmkt_fps_mode_resp_t fps_mode_resp; + bmkt_get_version_resp_t get_version_resp; + bmkt_get_db_capacity_resp_t db_cap_resp; + bmkt_set_sec_level_resp_t sec_level_resp; + bmkt_del_all_users_resp_t del_all_users_resp; + bmkt_enroll_templates_resp_t enroll_templates_resp; + bmkt_del_user_resp_t del_user_resp; + bmkt_enrolled_fingers_resp_t enrolled_fingers_resp; +} bmkt_response_data_t; + +/** +* bmkt_response: +* Structure to abstract different response structure types in one API +* to be used in bmkt_resp_cb_t callback function. +*/ +typedef struct bmkt_response +{ + int response_id; /**< Response message ID, one of th BMKT_RSP_XXX */ + int result; /**< Operation execution result code */ + int complete; /**< Operation completion status 1: complete / 0: not completed */ + bmkt_response_data_t response; /**< Operation specific response union */ +} bmkt_response_t; + +#endif /* _BMKT_RESPONSE_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/crc.h b/libfprint/drivers/synaptics/include/crc.h new file mode 100644 index 0000000..f3899a9 --- /dev/null +++ b/libfprint/drivers/synaptics/include/crc.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef CRC_H_ +#define CRC_H_ + +#include + +uint32_t compute_crc32(uint8_t *data, uint8_t length, uint32_t prev_crc32); + +enum checksum_crc_polynomial +{ + CHECKSUM_CRC_POLY1, /* polynomial: 0xedb88320 */ + CHECKSUM_CRC_POLY2 /* polynomial: 0x04c11db7 */ +}; + +int crc_checksum(uint32_t initialValue, uint32_t *checksum, uint8_t *msg, uint32_t len, uint32_t poly); + +#endif /* CRC_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/event.h b/libfprint/drivers/synaptics/include/event.h new file mode 100644 index 0000000..94e5c75 --- /dev/null +++ b/libfprint/drivers/synaptics/include/event.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef _EVENT_H_ +#define _EVENT_H_ + +#include "bmkt_internal.h" + +int bmkt_event_init(bmkt_event_t *event); +int bmkt_event_set(bmkt_event_t *event); +int bmkt_event_wait(bmkt_event_t *event, int timeout); +int bmkt_event_try(bmkt_event_t *event); +int bmkt_event_clear(bmkt_event_t *event); +int bmkt_event_destroy(bmkt_event_t *event); + +#endif /* _EVENT_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/mutex.h b/libfprint/drivers/synaptics/include/mutex.h new file mode 100644 index 0000000..10eab40 --- /dev/null +++ b/libfprint/drivers/synaptics/include/mutex.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef _MUTEX_H_ +#define _MUTEX_H_ + +#include "bmkt_internal.h" + +int bmkt_mutex_init(bmkt_mutex_t *mutex); +int bmkt_mutex_destroy(bmkt_mutex_t *mutex); +int bmkt_mutex_lock(bmkt_mutex_t *mutex); +int bmkt_mutex_unlock(bmkt_mutex_t *mutex); + +#endif /* _MUTEX_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/platform/linux/platform.h b/libfprint/drivers/synaptics/include/platform/linux/platform.h new file mode 100644 index 0000000..ab2cdda --- /dev/null +++ b/libfprint/drivers/synaptics/include/platform/linux/platform.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef _PLATFORM_H_ +#define _PLATFORM_H_ + +#include +#include +#include +#include + +#include "posix.h" +#include "event.h" +#include "plat_thread.h" +#include "thread.h" + +int bmkt_log(const char *format, ...); +int bmkt_log_open(const char *log_file); +int bmkt_log_close(void); + +#ifdef FULL_LOGGING +#define bmkt_dbg_log(format, ...) bmkt_log(format, ##__VA_ARGS__) +#define bmkt_info_log(format, ...) bmkt_log(format, ##__VA_ARGS__) +#define bmkt_warn_log(format, ...) bmkt_log(format, ##__VA_ARGS__) +#define bmkt_err_log(format, ...) bmkt_log(format, ##__VA_ARGS__) +#else +#define bmkt_dbg_log(format, ...) +#define bmkt_info_log(format, ...) +#define bmkt_warn_log(format, ...) bmkt_log(format, ##__VA_ARGS__) +#define bmkt_err_log(format, ...) bmkt_log(format, ##__VA_ARGS__) +#endif + +typedef struct bmkt_event +{ + sem_t event_sem; +} bmkt_event_t; + +#endif /* _PLATFORM_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/platform/posix/plat_thread.h b/libfprint/drivers/synaptics/include/platform/posix/plat_thread.h new file mode 100644 index 0000000..7ef5f88 --- /dev/null +++ b/libfprint/drivers/synaptics/include/platform/posix/plat_thread.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef _PLAT_THREAD_H_ +#define _PLAT_THREAD_H_ + +#include + +typedef struct plat_thread +{ + pthread_t thread; + void *ctx; +} plat_thread_t; + +#endif /* _PLAT_THREAD_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/platform/posix/posix.h b/libfprint/drivers/synaptics/include/platform/posix/posix.h new file mode 100644 index 0000000..d0d0afb --- /dev/null +++ b/libfprint/drivers/synaptics/include/platform/posix/posix.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef _POSIX_H_ +#define _POSIX_H_ + +int bmkt_sleep(int ms); +void *bmkt_interrupt_thread(void *ctx); + + +typedef struct bmkt_mutex +{ + pthread_mutex_t mutex; +} bmkt_mutex_t; + +#endif /* _POSIX_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/sensor.h b/libfprint/drivers/synaptics/include/sensor.h new file mode 100644 index 0000000..25d87d2 --- /dev/null +++ b/libfprint/drivers/synaptics/include/sensor.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef _SENSOR_H_ +#define _SENSOR_H_ + +#include "transport.h" +#include "event.h" +#include "thread.h" + +#define BMKT_MAX_PENDING_SESSIONS 2 + +typedef enum bmkt_sensor_state +{ + BMKT_SENSOR_STATE_UNINIT = 0, + BMKT_SENSOR_STATE_IDLE, + BMKT_SENSOR_STATE_INIT, + BMKT_SENSOR_STATE_EXIT, +} bmkt_sensor_state_t; + +typedef struct bmkt_sensor_drv bmkt_sensor_drv_t; + +typedef struct bmkt_sensor_version +{ + uint32_t build_time; + uint32_t build_num; + uint8_t version_major; + uint8_t version_minor; + uint8_t target; + uint8_t product; + uint8_t silicon_rev; + uint8_t formal_release; + uint8_t platform; + uint8_t patch; + uint8_t serial_number[6]; + uint16_t security; + uint8_t iface; + uint8_t device_type; +} bmkt_sensor_version_t; + +typedef struct bmkt_sensor +{ + bmkt_transport_t xport; + bmkt_sensor_version_t version; + bmkt_session_ctx_t pending_sessions[BMKT_MAX_PENDING_SESSIONS]; + int empty_session_idx; + int expect_response; + int flags; + int seq_num; + bmkt_event_t interrupt_event; + bmkt_sensor_state_t sensor_state; + bmkt_event_cb_t finger_event_cb; + void *finger_cb_ctx; + bmkt_general_error_cb_t gen_err_cb; + void *gen_err_cb_ctx; +#ifdef THREAD_SUPPORT + bmkt_thread_t interrupt_thread; + bmkt_mutex_t interrupt_mutex; +#endif /* THREAD_SUPPORT */ +} bmkt_sensor_t; + +int bmkt_sensor_open(bmkt_sensor_t *sensor, const bmkt_sensor_desc_t *desc, + bmkt_general_error_cb_t err_cb, void *err_cb_ctx); +int bmkt_sensor_close(bmkt_sensor_t *sensor); + +int bmkt_sensor_init_fps(bmkt_sensor_t *sensor); + +int bmkt_sensor_send_message(bmkt_sensor_t *sensor, uint8_t msg_id, uint8_t payload_size, + uint8_t *payload, bmkt_resp_cb_t resp_cb, void *resp_data); +int bmkt_sensor_send_message_sync(bmkt_sensor_t *sensor, uint8_t msg_id, uint8_t payload_size, + uint8_t *payload, uint8_t **resp_buf, int *resp_len, bmkt_response_t *resp); +int bmkt_sensor_handle_response(bmkt_sensor_t *sensor, uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp); +int bmkt_sensor_handle_interrupt(bmkt_sensor_t *sensor); + +int bmkt_sensor_process_pending_interrupts(bmkt_sensor_t *sensor); +#endif /* _SENSOR_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/synaptics.h b/libfprint/drivers/synaptics/include/synaptics.h new file mode 100644 index 0000000..883cfc2 --- /dev/null +++ b/libfprint/drivers/synaptics/include/synaptics.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef __synaptics_h__ +#define __synaptics_h__ + +#define SYNAPTICS_VENDOR_ID 0x06cb +#define SYNAPTICS_PRODUCT_ID_A9 0x00a9 + +/* Number of enroll stages */ +#define ENROLL_SAMPLES 8 + +#define SYNAPTICS_DRIVER_FULLNAME "Synaptics Sensors" +#include "bmkt.h" +#include "bmkt_response.h" + + +struct syna_enroll_resp_data +{ + int progress; +}; +typedef enum syna_state +{ + SYNA_STATE_UNINIT = 0, + SYNA_STATE_IDLE , + SYNA_STATE_ENROLL , + SYNA_STATE_IDENTIFY , + SYNA_STATE_IDENTIFY_DELAY_RESULT , + SYNA_STATE_VERIFY , + SYNA_STATE_VERIFY_DELAY_RESULT , +} syna_state_t; + +typedef struct synaptics_dev_s +{ + void *hImage; + void *pEnrollData; + void *pCtx; + bmkt_ctx_t *ctx; + bmkt_sensor_desc_t sensor_desc; + bmkt_sensor_t *sensor; + bmkt_usb_config_t *usb_config; + struct syna_enroll_resp_data enroll_resp_data; + gboolean isFingerOnSensor; + syna_state_t state; + pthread_mutex_t op_mutex; + pthread_cond_t op_cond; + int op_finished; + GSList* file_gslist; + GSList* sensor_gslist; +}synaptics_dev; + +#endif //__synaptics_h__ diff --git a/libfprint/drivers/synaptics/include/thread.h b/libfprint/drivers/synaptics/include/thread.h new file mode 100644 index 0000000..945f34f --- /dev/null +++ b/libfprint/drivers/synaptics/include/thread.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef _THREAD_H_ +#define _THREAD_H_ + +#include "plat_thread.h" + +typedef enum +{ + BMKT_THREAD_STATE_UNINITIALIZED = 0, + BMKT_THREAD_STATE_RUNNING, + BMKT_THREAD_STATE_FINISHED, +} bmkt_thread_state_t; + +#ifdef WIN32 +typedef DWORD(WINAPI *thread_func_t)(LPVOID lpThreadParameter); +#else +typedef void * (*thread_func_t)(void *ctx); +#endif + +typedef struct bmkt_thread +{ + bmkt_thread_state_t state; + plat_thread_t plat_thread; +} bmkt_thread_t; + +int bmkt_thread_create(bmkt_thread_t *thread, thread_func_t fn, void *ctx); +int bmkt_thread_destroy(bmkt_thread_t *thread); + +#endif /* _THREAD_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/transport/transport.h b/libfprint/drivers/synaptics/include/transport/transport.h new file mode 100644 index 0000000..2794d5b --- /dev/null +++ b/libfprint/drivers/synaptics/include/transport/transport.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef _TRANSPORT_H_ +#define _TRANSPORT_H_ + +#include "bmkt_internal.h" + +#ifdef THREAD_SUPPORT +#include "mutex.h" +#endif /* THREAD_SUPPORT */ + + +#include "usb_transport.h" + +#define BMKT_MAX_TRANSFER_LEN 263 + 1 /* SPI Header */ + 2 /* VCSFW header */ + +#define BMKT_XPORT_INT_NONE 0x0 +#define BMKT_XPORT_INT_RESPONSE 0x1 +#define BMKT_XPORT_INT_FINGER 0x2 +#define BMKT_XPORT_INT_ASYNC 0x4 + +typedef struct bmkt_transport_drv bmkt_transport_drv_t; + +typedef union +{ + bmkt_usb_transport_t usb_xport; +} bmtk_transport_data_t; + +typedef struct bmkt_transport +{ + bmkt_transport_type_t xport_type; + bmkt_transport_config_t xport_config; + const bmkt_transport_drv_t *drv; + bmkt_sensor_t *sensor; +#ifdef THREAD_SUPPORT + bmkt_mutex_t transfer_buffer_mutex; +#endif /* THREAD_SUPPORT */ + uint8_t transfer[BMKT_MAX_TRANSFER_LEN]; + bmtk_transport_data_t xport_data; +} bmkt_transport_t; + +struct bmkt_transport_drv +{ + int (*open)(bmkt_transport_t *xport, const bmkt_transport_config_t *xport_config); + int (*close)(bmkt_transport_t *xport); + + int (*send_command)(bmkt_transport_t *xport, int len); + int (*receive_response)(bmkt_transport_t *xport, int *len); + int (*send_command_sync)(bmkt_transport_t *xport, int len, uint8_t **resp_buf, int *resp_len); + int (*get_command_buffer)(bmkt_transport_t *xport, uint8_t **cmd, int *len); + int (*get_response_buffer)(bmkt_transport_t *xport, uint8_t **resp, int *len); + int (*reset)(bmkt_transport_t *xport); + int (*read_interrupt_status)(bmkt_transport_t *xport, int *interupt_mask); +}; + +int bmkt_transport_open(bmkt_transport_t *xport, bmkt_transport_type_t xport_type, + const bmkt_transport_config_t *config, bmkt_sensor_t *sensor); +int bmkt_transport_close(bmkt_transport_t *xport); + +int bmkt_transport_get_command_buffer(bmkt_transport_t *xport, uint8_t **buf, int *len); +int bmkt_transport_release_command_buffer(bmkt_transport_t *xport); + +int bmkt_transport_get_response_buffer(bmkt_transport_t *xport, uint8_t **resp, int *len); +int bmkt_transport_release_response_buffer(bmkt_transport_t *xport); + +int bmkt_transport_send_command(bmkt_transport_t *xport, int len); +int bmkt_transport_send_command_sync(bmkt_transport_t *xport, int len, uint8_t **resp_buf, int *resp_len); + +int bmkt_transport_receive_response(bmkt_transport_t *xport, int *len); + +int bmkt_transport_read_interrupt_status(bmkt_transport_t *xport, int *interupt_mask); + +#endif /* _TRANSPORT_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/include/transport/usb_transport.h b/libfprint/drivers/synaptics/include/transport/usb_transport.h new file mode 100644 index 0000000..573d087 --- /dev/null +++ b/libfprint/drivers/synaptics/include/transport/usb_transport.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#ifndef _USB_TRANSPORT_H_ +#define _USB_TRANSPORT_H_ + +#include "libusb-1.0/libusb.h" +#include "thread.h" + +#define USB_DEFAULT_CONFIGURATION 0 +#define USB_DEFAULT_INTERFACE 0 +#define USB_DEFAULT_ALT_SETTING 0 + +#define USB_EP_REQUEST 0x01 +#define USB_EP_REPLY 0x81 +#define USB_EP_FINGERPRINT 0x82 +#define USB_EP_INTERRUPT 0x83 + +#define USB_INTERRUPT_DATA_SIZE 7 + +typedef struct bmkt_usb_transport +{ + libusb_context *ctx; + libusb_device *device; + libusb_device_handle *handle; + bmkt_thread_t interrupt_thread; + int interrupt_mask; + uint8_t interrupt_data[USB_INTERRUPT_DATA_SIZE]; + int completed; +} bmkt_usb_transport_t; + +#endif /* _USB_TRANSPORT_H_ */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/src/auth.c b/libfprint/drivers/synaptics/src/auth.c new file mode 100644 index 0000000..0069f19 --- /dev/null +++ b/libfprint/drivers/synaptics/src/auth.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#include "bmkt_internal.h" +#include "sensor.h" + +int bmkt_identify(bmkt_sensor_t *sensor, bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_ID_USER, 0, NULL, resp_cb, cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_verify(bmkt_sensor_t *sensor, bmkt_user_id_t *user, + bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + uint8_t payload[BMKT_MAX_USER_ID_LEN + 1]; + uint8_t payload_len; + + if (sensor == NULL || user == NULL || user->user_id == NULL) + { + return BMKT_INVALID_PARAM; + } + + if (user->user_id_len == 0 || user->user_id_len > BMKT_MAX_USER_ID_LEN) + { + return BMKT_INVALID_PARAM; + } + + payload_len = user->user_id_len; + memset(payload, 0, sizeof(payload)); + memcpy(&payload[0], user->user_id, user->user_id_len); + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_VERIFY_USER, payload_len, payload, resp_cb, + cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} diff --git a/libfprint/drivers/synaptics/src/bmkt.c b/libfprint/drivers/synaptics/src/bmkt.c new file mode 100644 index 0000000..bc1f77f --- /dev/null +++ b/libfprint/drivers/synaptics/src/bmkt.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#include "bmkt_internal.h" +#include "bmkt_message.h" +#include "sensor.h" + +struct bmkt_ctx +{ + bmkt_sensor_t sensor; +}; + +bmkt_ctx_t g_ctx; + +int bmkt_init(bmkt_ctx_t **ctx) +{ + if (ctx == NULL) + { + return BMKT_INVALID_PARAM; + } + + memset(&g_ctx, 0, sizeof(bmkt_ctx_t)); + *ctx = &g_ctx; + + bmkt_log_open("bmkt.log"); + bmkt_dbg_log("%s: context size: %ld\n", __func__, sizeof(bmkt_ctx_t)); + return BMKT_SUCCESS; +} + +void bmkt_exit(bmkt_ctx_t *ctx) +{ + bmkt_log_close(); + + if (ctx == NULL) + { + return; + } +} + +int bmkt_open(bmkt_ctx_t *ctx, const bmkt_sensor_desc_t *desc, bmkt_sensor_t **sensor, + bmkt_general_error_cb_t err_cb, void *err_cb_ctx) +{ + int ret; + + if (ctx == NULL || sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + *sensor = &ctx->sensor; + + memset(*sensor, 0, sizeof(bmkt_sensor_t)); + + ret = bmkt_sensor_open(*sensor, desc, err_cb, err_cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_init_fps(bmkt_sensor_t *sensor) +{ + int ret; + uint8_t *resp_buf; + int resp_len; + bmkt_response_t resp; + + if (sensor->sensor_state != BMKT_SENSOR_STATE_UNINIT) + { + //sensor is already initialized + return BMKT_OPERATION_DENIED; + } + ret = bmkt_sensor_send_message_sync(sensor, BMKT_CMD_FPS_INIT, 0, NULL, &resp_buf, &resp_len, &resp); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + if (resp.result != BMKT_SUCCESS) + { + return resp.result; + } + + return bmkt_sensor_init_fps(sensor); +} + +int bmkt_close(bmkt_sensor_t *sensor) +{ + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + return bmkt_sensor_close(sensor); +} + +int bmkt_cancel_op(bmkt_sensor_t *sensor, bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_CANCEL_OP, 0, NULL, resp_cb, cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_get_fps_mode(bmkt_sensor_t *sensor, bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_GET_FPS_MODE, 0, NULL, resp_cb, cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_get_security_level(bmkt_sensor_t *sensor, bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_GET_SECURITY_LEVEL, 0, NULL, resp_cb, cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_set_security_level(bmkt_sensor_t *sensor, bmkt_sec_level_t level, bmkt_resp_cb_t resp_cb, + void *cb_ctx) +{ + int ret; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + if(level != BMKT_SECURITY_LEVEL_LOW && level != BMKT_SECURITY_LEVEL_MEDIUM && + level != BMKT_SECURITY_LEVEL_HIGH) + { + return BMKT_INVALID_PARAM; + } + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_SET_SECURITY_LEVEL, 1, (uint8_t*)&level, + resp_cb, cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_delete_enrolled_user(bmkt_sensor_t *sensor, uint8_t finger_id, const char *user_id, uint32_t user_id_len, + bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + uint8_t payload[BMKT_MAX_USER_ID_LEN + sizeof(finger_id)]; + uint8_t payload_len; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + if (user_id_len > BMKT_MAX_USER_ID_LEN) + { + return BMKT_INVALID_PARAM; + } + + memset(payload, 0, sizeof(payload)); + payload_len = user_id_len + sizeof(finger_id); + payload[0] = finger_id; + memcpy(&payload[1], user_id, user_id_len); + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_DEL_USER_FP, payload_len, payload, resp_cb, cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_delete_all_enrolled_users(bmkt_sensor_t *sensor, bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_DEL_FULL_DB, 0, NULL, resp_cb, cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_db_capacity(bmkt_sensor_t *sensor, bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_GET_DATABASE_CAPACITY, 0, NULL, resp_cb, + cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_get_enrolled_users(bmkt_sensor_t *sensor, bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_GET_TEMPLATE_RECORDS, 0, NULL, resp_cb, cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_get_enrolled_fingers(bmkt_sensor_t *sensor, const char *user_id, uint32_t user_id_len, + bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + uint8_t payload[BMKT_MAX_USER_ID_LEN]; + uint8_t payload_len; + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + if (user_id_len > BMKT_MAX_USER_ID_LEN) + { + return BMKT_INVALID_PARAM; + } + + memset(payload, 0, sizeof(payload)); + payload_len = user_id_len; + memcpy(&payload[0], user_id, user_id_len); + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_GET_ENROLLED_FINGERS, payload_len, payload, + resp_cb, cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_get_version(bmkt_sensor_t *sensor, bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_GET_VERSION, 0, NULL, resp_cb, + cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_process_pending_interrupts(bmkt_sensor_t *sensor) +{ + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + return bmkt_sensor_process_pending_interrupts(sensor); +} diff --git a/libfprint/drivers/synaptics/src/bmkt_message.c b/libfprint/drivers/synaptics/src/bmkt_message.c new file mode 100644 index 0000000..5136d24 --- /dev/null +++ b/libfprint/drivers/synaptics/src/bmkt_message.c @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#include "bmkt_internal.h" +#include "bmkt_response.h" +#include "bmkt_message.h" +#include "transport.h" +#include "sensor.h" + +static int parse_error_response(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + if (msg_resp->payload_len != 2) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + resp->result = (msg_resp->payload[0] << 8) | msg_resp->payload[1]; + + return BMKT_SUCCESS; +} + +static int parse_fps_mode_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + int offset = 0; + bmkt_fps_mode_resp_t *fps_mode_resp = &resp->response.fps_mode_resp; + + if (msg_resp->payload_len != sizeof(bmkt_fps_mode_resp_t)) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + fps_mode_resp->mode = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + fps_mode_resp->level2_mode = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + fps_mode_resp->cmd_id = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + fps_mode_resp->finger_presence = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + + return BMKT_SUCCESS; +} + +static int parse_enroll_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp; + + if (msg_resp->payload_len != 1) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + enroll_resp->progress = extract8(msg_resp->payload, NULL, BYTE_ORDER_SENSOR); + + return BMKT_SUCCESS; +} + +static int parse_enroll_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp; + + if (msg_resp->payload_len < 1 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 1)) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + enroll_resp->finger_id = msg_resp->payload[0]; + memcpy(enroll_resp->user_id, &msg_resp->payload[1], msg_resp->payload_len - 1); + + return BMKT_SUCCESS; +} + +static int parse_auth_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_identify_resp_t *id_resp = &resp->response.id_resp; + + if (msg_resp->payload_len < 3 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 3)) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + id_resp->match_result = (double)msg_resp->payload[0] + 0.01 * (double)msg_resp->payload[1]; + id_resp->finger_id = msg_resp->payload[2]; + memcpy(id_resp->user_id, &msg_resp->payload[3], msg_resp->payload_len - 3); + + return BMKT_SUCCESS; +} + +static int parse_security_level_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_set_sec_level_resp_t *sec_level_resp = &resp->response.sec_level_resp; + + if (msg_resp->payload_len != 1) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + sec_level_resp->sec_level = extract8(msg_resp->payload, NULL, BYTE_ORDER_SENSOR); + + return BMKT_SUCCESS; +} + +static int parse_del_all_users_progress_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_del_all_users_resp_t *del_all_users_resp = &resp->response.del_all_users_resp; + + if (msg_resp->payload_len != 1) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + del_all_users_resp->progress = extract8(msg_resp->payload, NULL, BYTE_ORDER_SENSOR); + + return BMKT_SUCCESS; +} + +static int parse_db_cap_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_get_db_capacity_resp_t *db_cap_resp = &resp->response.db_cap_resp; + int offset = 0; + + if (msg_resp->payload_len < 2 || msg_resp->payload_len > 4) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + db_cap_resp->total = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + db_cap_resp->empty = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + + if (msg_resp->payload_len == 4) + { + db_cap_resp->bad_slots = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + db_cap_resp->corrupt_templates = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + } + + return BMKT_SUCCESS; +} + +static int parse_get_enrolled_fingers_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + int offset = 0; + int i = 0; + + if (msg_resp->payload_len < 2) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + // 2 bytes per finger so calculate the total number of fingers to process + int num_fingers = (msg_resp->payload_len) / 2; + + bmkt_enrolled_fingers_resp_t *get_enrolled_fingers_resp = &resp->response.enrolled_fingers_resp; + + for (i = 0; i < num_fingers; i++) + { + get_enrolled_fingers_resp->fingers[i].finger_id = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + get_enrolled_fingers_resp->fingers[i].template_status = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + + } + return BMKT_SUCCESS; +} +static int parse_get_enrolled_users_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + int offset = 0; + int i = 0; + + // the payload is 2 bytes + template data + if (msg_resp->payload_len < 2) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + bmkt_enroll_templates_resp_t *get_enroll_templates_resp = &resp->response.enroll_templates_resp; + + get_enroll_templates_resp->total_query_messages = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + get_enroll_templates_resp->query_sequence = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + + int n = 0; + for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++) + { + if (offset >= msg_resp->payload_len) + break; + get_enroll_templates_resp->templates[n].user_id_len = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR) - 2; + if(get_enroll_templates_resp->templates[n].user_id_len > BMKT_MAX_USER_ID_LEN) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + get_enroll_templates_resp->templates[n].template_status = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + get_enroll_templates_resp->templates[n].finger_id = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + for (i = 0; i < get_enroll_templates_resp->templates[n].user_id_len; i++) + { + get_enroll_templates_resp->templates[n].user_id[i] = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + } + get_enroll_templates_resp->templates[n].user_id[i] = '\0'; + } + + return BMKT_SUCCESS; +} + +static int parse_get_version_report(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + bmkt_get_version_resp_t *get_version_resp = &resp->response.get_version_resp; + int offset = 0; + + if (msg_resp->payload_len != 15) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + memcpy(get_version_resp->part, msg_resp->payload, BMKT_PART_NUM_LEN); + offset += BMKT_PART_NUM_LEN; + get_version_resp->year = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + get_version_resp->week = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + get_version_resp->patch = extract8(msg_resp->payload, &offset, BYTE_ORDER_SENSOR); + memcpy(get_version_resp->supplier_id, msg_resp->payload + offset, BMKT_SUPPLIER_ID_LEN); + + return BMKT_SUCCESS; +} + +int bmkt_compose_message(uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num, + uint8_t payload_size, uint8_t *payload) +{ + int message_len = BMKT_MESSAGE_HEADER_LEN + payload_size; + + if (*cmd_len < message_len) + { + return BMKT_OUT_OF_MEMORY; + } + + cmd[BMKT_MESSAGE_HEADER_ID_FIELD] = BMKT_MESSAGE_HEADER_ID; + cmd[BMKT_MESSAGE_SEQ_NUM_FIELD] = seq_num; + cmd[BMKT_MESSAGE_ID_FIELD] = msg_id; + cmd[BMKT_MESSAGE_PAYLOAD_LEN_FIELD] = payload_size; + memcpy(&cmd[BMKT_MESSAGE_PAYLOAD_FIELD], payload, payload_size); + + *cmd_len = message_len; + + return BMKT_SUCCESS; +} + +int bmkt_parse_message_header(uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp) +{ + if (resp_buf[BMKT_MESSAGE_HEADER_ID_FIELD] != BMKT_MESSAGE_HEADER_ID) + { + return BMKT_CORRUPT_MESSAGE; + } + + msg_resp->seq_num = resp_buf[BMKT_MESSAGE_SEQ_NUM_FIELD]; + msg_resp->msg_id = resp_buf[BMKT_MESSAGE_ID_FIELD]; + msg_resp->payload_len = resp_buf[BMKT_MESSAGE_PAYLOAD_LEN_FIELD]; + if (msg_resp->payload_len > 0) + { + msg_resp->payload = &resp_buf[BMKT_MESSAGE_PAYLOAD_FIELD]; + } + else + { + msg_resp->payload = NULL; + } + + return BMKT_SUCCESS; +} + +int bmkt_parse_message_payload(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp) +{ + int ret = BMKT_SUCCESS; + + memset(resp, 0, sizeof(bmkt_response_t)); + + resp->response_id = msg_resp->msg_id; + + switch(msg_resp->msg_id) + { + case BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL: + case BMKT_RSP_SENSOR_MODULE_TEST_FAIL: + case BMKT_RSP_FPS_INIT_FAIL: + case BMKT_RSP_FPS_MODE_FAIL: + case BMKT_RSP_SET_SECURITY_LEVEL_FAIL: + case BMKT_RSP_GET_SECURITY_LEVEL_FAIL: + case BMKT_RSP_CANCEL_OP_FAIL: + case BMKT_RSP_ENROLL_FAIL: + case BMKT_RSP_ID_FAIL: + case BMKT_RSP_VERIFY_FAIL: + case BMKT_RSP_QUERY_FAIL: + case BMKT_RSP_DEL_USER_FP_FAIL: + case BMKT_RSP_DEL_FULL_DB_FAIL: + case BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL: + case BMKT_RSP_POWER_DOWN_FAIL: + case BMKT_RSP_GET_VERSION_FAIL: + case BMKT_RSP_DISABLE_PAIRING_FAIL: + case BMKT_RSP_QUERY_PAIRING_FAIL: + case BMKT_RSP_SENSOR_STATUS_FAIL: + case BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL: + ret = parse_error_response(msg_resp, resp); + resp->complete = 1; + break; + + case BMKT_RSP_FPS_INIT_OK: + case BMKT_RSP_CANCEL_OP_OK: + case BMKT_RSP_DEL_FULL_DB_OK: + case BMKT_RSP_DEL_USER_FP_OK: + // responses with a payload of 0 + // so the response indicates success + resp->result = BMKT_SUCCESS; + resp->complete = 1; + break; + + case BMKT_RSP_FPS_MODE_REPORT: + // parse_fps_mode + ret = parse_fps_mode_report(msg_resp, resp); + resp->complete = 1; + break; + + case BMKT_RSP_GET_SECURITY_LEVEL_REPORT: + case BMKT_RSP_SET_SECURITY_LEVEL_REPORT: + // parse security level result + ret = parse_security_level_report(msg_resp, resp); + resp->complete = 1; + break; + + case BMKT_RSP_DELETE_PROGRESS: + ret = parse_del_all_users_progress_report(msg_resp, resp); + break; + + case BMKT_RSP_CAPTURE_COMPLETE: + resp->result = BMKT_SUCCESS; + break; + + case BMKT_RSP_ENROLL_READY: + resp->result = BMKT_SUCCESS; + break; + + case BMKT_RSP_ENROLL_REPORT: + ret = parse_enroll_report(msg_resp, resp); + break; + + case BMKT_RSP_ENROLL_OK: + resp->complete = 1; + ret = parse_enroll_ok(msg_resp, resp); + break; + + case BMKT_RSP_ID_OK: + case BMKT_RSP_VERIFY_OK: + ret = parse_auth_ok(msg_resp, resp); + resp->complete = 1; + break; + case BMKT_RSP_GET_ENROLLED_FINGERS_REPORT: + ret = parse_get_enrolled_fingers_report(msg_resp, resp); + resp->complete = 1; + break; + case BMKT_RSP_DATABASE_CAPACITY_REPORT: + resp->complete = 1; + ret = parse_db_cap_report(msg_resp, resp); + break; + case BMKT_RSP_TEMPLATE_RECORDS_REPORT: + ret = parse_get_enrolled_users_report(msg_resp, resp); + break; + case BMKT_RSP_QUERY_RESPONSE_COMPLETE: + resp->complete = 1; + break; + + case BMKT_RSP_VERSION_INFO: + ret = parse_get_version_report(msg_resp, resp); + resp->complete = 1; + break; + } + + return ret; +} diff --git a/libfprint/drivers/synaptics/src/crc.c b/libfprint/drivers/synaptics/src/crc.c new file mode 100644 index 0000000..d9e1cec --- /dev/null +++ b/libfprint/drivers/synaptics/src/crc.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#include "bmkt_internal.h" +#include "crc.h" + +static const uint32_t Crc32Lookup16[16] = +{ + 0x00000000,0x1DB71064,0x3B6E20C8,0x26D930AC,0x76DC4190,0x6B6B51F4,0x4DB26158,0x5005713C, + 0xEDB88320,0xF00F9344,0xD6D6A3E8,0xCB61B38C,0x9B64C2B0,0x86D3D2D4,0xA00AE278,0xBDBDF21C +}; + +uint32_t compute_crc32(uint8_t *data, uint8_t length, uint32_t prev_crc32) +{ + uint32_t crc = ~prev_crc32; + const uint8_t* current = (const uint8_t*) data; + + while (length-- != 0) + { + crc = Crc32Lookup16[(crc ^ *current ) & 0x0F] ^ (crc >> 4); + crc = Crc32Lookup16[(crc ^ (*current >> 4)) & 0x0F] ^ (crc >> 4); + current++; + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + +static const uint32_t crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +/* Polynomial : 0x04c11db7 */ +/* + * A table of precomputed CRC values. + * This table was computed using a polynomial of 0x[1]04c11b7 + * (which reversed is 0xedb88320.[8]). This + * is the standard CRC-32 polynomial used with HDLC, Ethernet, etc. + * Note that this used the 'big endian' flag -e. +*/ + +static const uint32_t crc_poly2_table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, /* [ 0.. 3] */ + 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, /* [ 4.. 7] */ + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, /* [ 8.. 11] */ + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, /* [ 12.. 15] */ + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, /* [ 16.. 19] */ + 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, /* [ 20.. 23] */ + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, /* [ 24.. 27] */ + 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, /* [ 28.. 31] */ + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, /* [ 32.. 35] */ + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, /* [ 36.. 39] */ + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, /* [ 40.. 43] */ + 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, /* [ 44.. 47] */ + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, /* [ 48.. 51] */ + 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, /* [ 52.. 55] */ + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, /* [ 56.. 59] */ + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, /* [ 60.. 63] */ + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, /* [ 64.. 67] */ + 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, /* [ 68.. 71] */ + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, /* [ 72.. 75] */ + 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, /* [ 76.. 79] */ + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, /* [ 80.. 83] */ + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, /* [ 84.. 87] */ + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, /* [ 88.. 91] */ + 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, /* [ 92.. 95] */ + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, /* [ 96.. 99] */ + 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, /* [100..103] */ + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, /* [104..107] */ + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, /* [108..111] */ + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, /* [112..115] */ + 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, /* [116..119] */ + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, /* [120..123] */ + 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, /* [124..127] */ + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, /* [128..131] */ + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, /* [132..135] */ + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, /* [136..139] */ + 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, /* [140..143] */ + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, /* [144..147] */ + 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, /* [148..151] */ + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, /* [152..155] */ + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, /* [156..159] */ + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, /* [160..163] */ + 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, /* [164..167] */ + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, /* [168..171] */ + 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, /* [172..175] */ + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, /* [176..179] */ + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, /* [180..183] */ + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, /* [184..187] */ + 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, /* [188..191] */ + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, /* [192..195] */ + 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, /* [196..199] */ + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, /* [200..203] */ + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, /* [204..207] */ + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, /* [208..211] */ + 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, /* [212..215] */ + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, /* [216..219] */ + 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, /* [220..223] */ + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, /* [224..227] */ + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, /* [228..231] */ + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, /* [232..235] */ + 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, /* [236..239] */ + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, /* [240..243] */ + 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, /* [244..247] */ + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, /* [248..251] */ + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4, /* [252..255] */ +}; + +#define CRCDO1(msg) *checksum = crc_table[((int)*checksum ^ (*msg++)) & 0xff] ^ (*checksum >> 8); +#define CRCDO2(msg) CRCDO1(msg); CRCDO1(msg); +#define CRCDO4(msg) CRCDO2(msg); CRCDO2(msg); +#define CRCDO8(msg) CRCDO4(msg); CRCDO4(msg); + +int crc_checksum(uint32_t initialValue, uint32_t *checksum, uint8_t *msg, uint32_t len, uint32_t poly) +{ + int result = BMKT_SUCCESS; + + if (!checksum) + { + return BMKT_INVALID_PARAM; + } + + *checksum = initialValue; + + switch (poly) + { + case CHECKSUM_CRC_POLY1: + { + *checksum = *checksum ^ 0xffffffffL; + while (len >= 8) + { + CRCDO8(msg); + len -= 8; + } + + if (len) + { + do + { + CRCDO1(msg); + } while (--len); + } + + *checksum = *checksum ^ 0xffffffffL; + break; + } + + case CHECKSUM_CRC_POLY2: + { + while (len != 0) + { + *checksum = crc_poly2_table[((*msg++ << 24) ^ (*checksum)) >> 24] ^ (*checksum << 8); + len--; + } + + *checksum = ~(*checksum); + break; + } + + default: + result = BMKT_INVALID_PARAM; + break; + } + + return result; +} \ No newline at end of file diff --git a/libfprint/drivers/synaptics/src/enroll.c b/libfprint/drivers/synaptics/src/enroll.c new file mode 100644 index 0000000..fb793a9 --- /dev/null +++ b/libfprint/drivers/synaptics/src/enroll.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#include "bmkt_internal.h" +#include "sensor.h" + +int bmkt_enroll(bmkt_sensor_t *sensor, const uint8_t *user_id, uint32_t user_id_len, + uint8_t finger_id, bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + uint8_t payload[BMKT_MAX_USER_ID_LEN + 1]; + uint8_t payload_len; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + if (user_id_len > BMKT_MAX_USER_ID_LEN) + { + return BMKT_INVALID_PARAM; + } + + payload_len = user_id_len + 1; + payload[0] = finger_id; + memcpy(&payload[1], user_id, user_id_len); + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_ENROLL_USER, payload_len, payload, resp_cb, + cb_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_enroll_pause(bmkt_sensor_t *sensor) +{ + int ret; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_ENROLL_PAUSE, 0, NULL, NULL, NULL); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_enroll_resume(bmkt_sensor_t *sensor) +{ + int ret; + + if (sensor == NULL) + { + return BMKT_INVALID_PARAM; + } + + ret = bmkt_sensor_send_message(sensor, BMKT_CMD_ENROLL_RESUME, 0, NULL, NULL, NULL); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + return BMKT_SUCCESS; +} \ No newline at end of file diff --git a/libfprint/drivers/synaptics/src/platform/linux/plat_event.c b/libfprint/drivers/synaptics/src/platform/linux/plat_event.c new file mode 100644 index 0000000..1161f4f --- /dev/null +++ b/libfprint/drivers/synaptics/src/platform/linux/plat_event.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#include +#include +#include +#include "event.h" + +int bmkt_event_init(bmkt_event_t *event) +{ + sem_init(&event->event_sem, 0, 0); + return BMKT_SUCCESS; +} + +int bmkt_event_set(bmkt_event_t *event) +{ + int ret; + + ret = sem_post(&event->event_sem); + if (ret) { + if (errno == EOVERFLOW) + return BMKT_GENERAL_ERROR; + else + return BMKT_INVALID_PARAM; + } + + return BMKT_SUCCESS; +} + +int bmkt_event_wait(bmkt_event_t *event, int timeout) +{ + int ret; + + if (timeout) { + struct timespec ts; + long nsec; + + clock_gettime(CLOCK_MONOTONIC, &ts); + nsec = ts.tv_nsec + (timeout % 1000) * 1000 * 1000; + ts.tv_nsec = nsec % (1000 * 1000 * 1000); + ts.tv_sec += (timeout / 1000) + (nsec / (1000 * 1000 * 1000)); + + for (;;) { + ret = sem_timedwait(&event->event_sem, &ts); + if (ret) { + bmkt_info_log("%s: sem_timedwait: %d\n", __func__, ret); + if (errno == EINTR) { + continue; + } else if (errno == ETIMEDOUT) { + ret = BMKT_OP_TIME_OUT; + } else { + ret = BMKT_GENERAL_ERROR; + } + } + break; + } + } else { + for (;;) { + ret = sem_wait(&event->event_sem); + if (ret) { + if (errno == EINTR) { + continue; + } else if (errno == EINVAL) { + return BMKT_INVALID_PARAM; + } else { + return BMKT_GENERAL_ERROR; + } + } + break; + } + } + + return BMKT_SUCCESS; +} + +int bmkt_event_try(bmkt_event_t *event) +{ + int ret; + + ret = sem_trywait(&event->event_sem); + if (ret) + return BMKT_EVENT_NOT_SET; + + return BMKT_SUCCESS; +} + +int bmkt_event_clear(bmkt_event_t *event) +{ + int ret; + + for (;;) { + ret = sem_trywait(&event->event_sem); + if (ret) { + if (errno == EAGAIN) { + break; + } else { + return BMKT_GENERAL_ERROR; + } + } + } + + return BMKT_SUCCESS; +} + +int bmkt_event_destroy(bmkt_event_t *event) +{ + sem_destroy(&event->event_sem); + return BMKT_SUCCESS; +} \ No newline at end of file diff --git a/libfprint/drivers/synaptics/src/platform/linux/plat_log.c b/libfprint/drivers/synaptics/src/platform/linux/plat_log.c new file mode 100644 index 0000000..4c5c2ca --- /dev/null +++ b/libfprint/drivers/synaptics/src/platform/linux/plat_log.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + + +#include "bmkt.h" +#include "platform.h" + +#include + +FILE *g_log_file; + +int bmkt_log_open(const char *log_file) +{ + if (log_file == NULL) + { + g_log_file = stdout; + return BMKT_SUCCESS; + } + + g_log_file = fopen(log_file, "w"); + if (g_log_file == NULL) + { + g_log_file = stdout; + return BMKT_GENERAL_ERROR; + } + + return BMKT_SUCCESS; +} + +int bmkt_log_close(void) +{ + if (g_log_file != stdout) + { + fclose(g_log_file); + } + + return BMKT_SUCCESS; +} + +int bmkt_log(const char *format, ...) +{ + va_list args; + + if (g_log_file == NULL) + { + return BMKT_GENERAL_ERROR; + } + + va_start(args, format); + vfprintf(g_log_file, format, args); + va_end(args); + + fflush(g_log_file); + + return BMKT_SUCCESS; +} diff --git a/libfprint/drivers/synaptics/src/platform/posix/plat_mutex.c b/libfprint/drivers/synaptics/src/platform/posix/plat_mutex.c new file mode 100644 index 0000000..b60c8ea --- /dev/null +++ b/libfprint/drivers/synaptics/src/platform/posix/plat_mutex.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ +#include "mutex.h" + +int bmkt_mutex_init(bmkt_mutex_t *mutex) +{ + pthread_mutex_init(&mutex->mutex, NULL); + return BMKT_SUCCESS; +} + +int bmkt_mutex_destroy(bmkt_mutex_t *mutex) +{ + int ret; + + ret = pthread_mutex_destroy(&mutex->mutex); + if (ret != 0) + { + return BMKT_GENERAL_ERROR; + } + + return BMKT_SUCCESS; +} + +int bmkt_mutex_lock(bmkt_mutex_t *mutex) +{ + int ret; + + ret = pthread_mutex_lock(&mutex->mutex); + if (ret) + { + return BMKT_GENERAL_ERROR; + } + + return BMKT_SUCCESS; +} + +int bmkt_mutex_unlock(bmkt_mutex_t *mutex) +{ + int ret; + + ret = pthread_mutex_unlock(&mutex->mutex); + if (ret) + { + return BMKT_GENERAL_ERROR; + } + + return BMKT_SUCCESS; +} \ No newline at end of file diff --git a/libfprint/drivers/synaptics/src/platform/posix/plat_thread.c b/libfprint/drivers/synaptics/src/platform/posix/plat_thread.c new file mode 100644 index 0000000..8e44607 --- /dev/null +++ b/libfprint/drivers/synaptics/src/platform/posix/plat_thread.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#include "bmkt_internal.h" + +int bmkt_thread_create(bmkt_thread_t *thread, thread_func_t fn, void *ctx) +{ + int ret; + + ret = pthread_create(&thread->plat_thread.thread, NULL, fn, ctx); + if (ret) + { + return BMKT_GENERAL_ERROR; + } + + thread->state = BMKT_THREAD_STATE_RUNNING; + return BMKT_SUCCESS; +} + +int bmkt_thread_destroy(bmkt_thread_t *thread) +{ + int ret; + void *thread_ret_val; + thread->state = BMKT_THREAD_STATE_FINISHED; + + ret = pthread_cancel(thread->plat_thread.thread); + if (ret) + { + return BMKT_GENERAL_ERROR; + } + + ret = pthread_join(thread->plat_thread.thread, &thread_ret_val); + if (ret) + { + return BMKT_GENERAL_ERROR; + } + + return BMKT_SUCCESS; +} \ No newline at end of file diff --git a/libfprint/drivers/synaptics/src/platform/posix/posix.c b/libfprint/drivers/synaptics/src/platform/posix/posix.c new file mode 100644 index 0000000..eab5f68 --- /dev/null +++ b/libfprint/drivers/synaptics/src/platform/posix/posix.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#include +#include +#include + +#include "bmkt_internal.h" +#include "sensor.h" + +int bmkt_sleep(int ms) +{ + struct timespec ts; + struct timespec rem; + + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000 * 1000; + for (;;) + { + if (nanosleep(&ts, &rem) == 0) + { + break; + } + else + { + if (errno == EINTR) + { + ts = rem; + continue; + } + return BMKT_GENERAL_ERROR; + } + } + + return BMKT_SUCCESS; +} + +#ifdef THREAD_SUPPORT +void *bmkt_interrupt_thread(void *ctx) +{ + int ret; + bmkt_sensor_t *sensor = (bmkt_sensor_t *)ctx; + + while (sensor->interrupt_thread.state != BMKT_THREAD_STATE_FINISHED + && sensor->sensor_state != BMKT_SENSOR_STATE_EXIT) + { + ret = bmkt_process_pending_interrupts(sensor); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to run state: %d\n", ret); + return (void*)BMKT_GENERAL_ERROR; + } + } + + return (void*)BMKT_SUCCESS; +} +#endif /* THREAD_SUPPORT */ \ No newline at end of file diff --git a/libfprint/drivers/synaptics/src/sensor.c b/libfprint/drivers/synaptics/src/sensor.c new file mode 100644 index 0000000..8d08318 --- /dev/null +++ b/libfprint/drivers/synaptics/src/sensor.c @@ -0,0 +1,653 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + + +#include "bmkt_internal.h" +#include "bmkt_message.h" +#include "sensor.h" + +#define SENSOR_CMD_GET_VERSION 1 +#define SENSOR_CMD_ACE_COMMAND 167 +#define SENSOR_CMD_ASYNCMSG_READ 168 + +#define SENSOR_FW_CMD_HEADER_LEN 1 +#define SENSOR_FW_REPLY_HEADER_LEN 2 + +static int get_version(bmkt_sensor_t *sensor, bmkt_sensor_version_t *mis_version) +{ + int ret; + uint8_t *resp = NULL; + int resp_len = 40; + uint16_t status = 0; + uint8_t *cmd; + int cmd_len = 0; + int cmd_buf_len; + int offset = 0; + + ret = bmkt_transport_get_command_buffer(&sensor->xport, &cmd, &cmd_buf_len); + if (ret != BMKT_SUCCESS) + { + return BMKT_OUT_OF_MEMORY; + } + + if (cmd_buf_len < SENSOR_FW_CMD_HEADER_LEN) + { + return BMKT_OUT_OF_MEMORY; + } + + encode8(SENSOR_CMD_GET_VERSION, cmd, &cmd_len, BYTE_ORDER_SENSOR); + + ret = bmkt_transport_send_command_sync(&sensor->xport, cmd_len, &resp, &resp_len); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + status = extract16(resp, &offset, BYTE_ORDER_SENSOR); + if (status) + { + bmkt_err_log("The sensor reported an error when sending get version command: 0x%x\n", + status); + return BMKT_SENSOR_MALFUNCTION; + } + + if (resp_len < 38) + { + return BMKT_SENSOR_MALFUNCTION; + } + + mis_version->build_time = extract32(resp, &offset, BYTE_ORDER_SENSOR); + mis_version->build_num = extract32(resp, &offset, BYTE_ORDER_SENSOR); + mis_version->version_major = extract8(resp, &offset, BYTE_ORDER_SENSOR); + mis_version->version_minor = extract8(resp, &offset, BYTE_ORDER_SENSOR); + mis_version->target = extract8(resp, &offset, BYTE_ORDER_SENSOR); + mis_version->product = extract8(resp, &offset, BYTE_ORDER_SENSOR); + + ret = bmkt_transport_release_command_buffer(&sensor->xport); + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("%s: failed to release command buffer: %d\n", __func__, ret); + return ret; + } + + return BMKT_SUCCESS; +} + +static bmkt_session_ctx_t *get_empty_session_ctx(bmkt_sensor_t *sensor) +{ + bmkt_session_ctx_t *ctx; + int i; + int idx; + + for (i = 0; i < BMKT_MAX_PENDING_SESSIONS; i++) + { + idx = (sensor->empty_session_idx + i) % BMKT_MAX_PENDING_SESSIONS; + ctx = &sensor->pending_sessions[idx]; + if (ctx->seq_num == 0) + { + sensor->empty_session_idx = (idx + 1) % BMKT_MAX_PENDING_SESSIONS; + return ctx; + } + } + + return NULL; +} + +static bmkt_session_ctx_t *get_session_ctx(bmkt_sensor_t *sensor, int seq_num) +{ + int i; + bmkt_session_ctx_t *ctx; + + // Sequence number of 0 is not valid for a response to + // a command. + if (seq_num == 0) + { + return NULL; + } + + for (i = 0; i < BMKT_MAX_PENDING_SESSIONS; i++) + { + ctx = &sensor->pending_sessions[i]; + if (ctx->seq_num == seq_num) + { + return ctx; + } + } + + return NULL; +} + +static int release_session_ctx(bmkt_sensor_t *sensor, bmkt_session_ctx_t *ctx) +{ + + memset(ctx, 0, sizeof(bmkt_session_ctx_t)); + + return BMKT_SUCCESS; +} + +int bmkt_sensor_open(bmkt_sensor_t *sensor, const bmkt_sensor_desc_t *desc, + bmkt_general_error_cb_t err_cb, void *err_cb_ctx) +{ + int ret; + + sensor->seq_num = 1; + sensor->flags = desc->flags; + + sensor->sensor_state = BMKT_SENSOR_STATE_UNINIT; + + ret = bmkt_transport_open(&sensor->xport, desc->xport_type, &desc->xport_config, sensor); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to open transport: %d\n", ret); + return ret; + } + + sensor->gen_err_cb = err_cb; + sensor->gen_err_cb_ctx = err_cb_ctx; + + ret = get_version(sensor, &sensor->version); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to get version info: %d\n", ret); + return ret; + } + + bmkt_dbg_log("Build Time: %d\n", sensor->version.build_time); + bmkt_dbg_log("Build Num: %d\n", sensor->version.build_num); + bmkt_dbg_log("Version: %d.%d\n", sensor->version.version_major, sensor->version.version_minor); + bmkt_dbg_log("Target: %d\n", sensor->version.target); + bmkt_dbg_log("Product: %d\n", sensor->version.product); + + ret = bmkt_event_init(&sensor->interrupt_event); + if (ret != BMKT_SUCCESS) + { + return ret; + } + +#ifdef THREAD_SUPPORT + ret = bmkt_mutex_init(&sensor->interrupt_mutex); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to initialize interrupt mutex: %d\n", ret); + return ret; + } + + ret = bmkt_thread_create(&sensor->interrupt_thread, bmkt_interrupt_thread, sensor); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to start interrupt thread: %d\n", ret); + return ret; + } +#endif /* THREAD_SUPPORT */ + + + return BMKT_SUCCESS; +} + +int bmkt_sensor_close(bmkt_sensor_t *sensor) +{ + int ret; + + sensor->sensor_state = BMKT_SENSOR_STATE_EXIT; + bmkt_event_set(&sensor->interrupt_event); + +#ifdef THREAD_SUPPORT + ret = bmkt_thread_destroy(&sensor->interrupt_thread); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to destroy interrupt thread: %d\n", ret); + return ret; + } + + bmkt_mutex_destroy(&sensor->interrupt_mutex); +#endif /* THREAD_SUPPORT */ + + ret = bmkt_event_destroy(&sensor->interrupt_event); + if (ret != BMKT_SUCCESS) + { + // warn + } + + ret = bmkt_transport_close(&sensor->xport); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + sensor->sensor_state = BMKT_SENSOR_STATE_EXIT; + return BMKT_SUCCESS; +} + +int bmkt_sensor_init_fps(bmkt_sensor_t *sensor) +{ + sensor->sensor_state = BMKT_SENSOR_STATE_INIT; + bmkt_event_set(&sensor->interrupt_event); + + return BMKT_SUCCESS; +} + +int bmkt_sensor_send_message(bmkt_sensor_t *sensor, uint8_t msg_id, uint8_t payload_size, + uint8_t *payload, bmkt_resp_cb_t resp_cb, void *cb_ctx) +{ + int ret; + uint8_t *cmd; + int cmd_buf_len = 0; + int msg_len; + int seq_num = 0; + bmkt_session_ctx_t *session_ctx = get_empty_session_ctx(sensor); + + if (session_ctx == NULL) + { + return BMKT_OPERATION_DENIED; + } + + if (sensor->seq_num > 255) { + // seq. number is in range [1 – 255]. After it reaches 255, it rolls over to 1 and starts over again. + // (0 is reserved for special purposes) + sensor->seq_num = 1; + } + session_ctx->seq_num = sensor->seq_num++; + session_ctx->resp_cb = resp_cb; + session_ctx->cb_ctx = cb_ctx; + + bmkt_dbg_log("session_ctx->seq_num=%d, sensor->seq_num=%d\n", session_ctx->seq_num, sensor->seq_num); + + for (;;) + { + ret = bmkt_transport_get_command_buffer(&sensor->xport, &cmd, &cmd_buf_len); + if (ret != BMKT_SUCCESS) + { + return BMKT_OUT_OF_MEMORY; + } + + // MIS sensors send ACE commands encapsulated in FW commands + cmd[0] = SENSOR_CMD_ACE_COMMAND; + msg_len = cmd_buf_len - SENSOR_FW_CMD_HEADER_LEN; + + if (session_ctx != NULL) + { + seq_num = session_ctx->seq_num; + } + + ret = bmkt_compose_message(&cmd[1], &msg_len, msg_id, seq_num, payload_size, payload); + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("Failed to compose ace message: %d\n", ret); + goto cleanup; + } + + ret = bmkt_transport_send_command(&sensor->xport, msg_len + SENSOR_FW_CMD_HEADER_LEN); + if (ret == BMKT_SENSOR_RESPONSE_PENDING) + { + bmkt_transport_release_command_buffer(&sensor->xport); + ret = bmkt_sensor_handle_interrupt(sensor); + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("bmkt_sensor_send_message: Failed to handle interrupt: %d\n", ret); + goto cleanup; + } + continue; + } + else if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("%s: failed to send ACE command: %d\n", __func__, ret); + goto cleanup; + } + break; + } + + sensor->expect_response = 1; + +cleanup: + bmkt_transport_release_command_buffer(&sensor->xport); + if (ret != BMKT_SUCCESS) + { + release_session_ctx(sensor, session_ctx); + } + + return ret; +} + +static int bmkt_sensor_send_async_read_command(bmkt_sensor_t *sensor) +{ + int ret; + uint8_t *cmd; + int cmd_buf_len = 0; + + ret = bmkt_transport_get_command_buffer(&sensor->xport, &cmd, &cmd_buf_len); + if (ret != BMKT_SUCCESS) + { + return BMKT_OUT_OF_MEMORY; + } + + // MIS sensors send ACE commands encapsulated in FW commands + cmd[0] = SENSOR_CMD_ASYNCMSG_READ; + + ret = bmkt_transport_send_command(&sensor->xport, SENSOR_FW_CMD_HEADER_LEN); + if (ret == BMKT_SENSOR_RESPONSE_PENDING) + { + // The caller needs to handle the response before we can send this command + goto cleanup; + } + else if (ret != BMKT_SUCCESS) + { + if (ret != BMKT_SENSOR_NOT_READY) + { + bmkt_dbg_log("%s: failed to send ACE ASYNC READ command: %d\n", __func__, ret); + } + goto cleanup; + } + + sensor->expect_response = 1; + +cleanup: + bmkt_transport_release_command_buffer(&sensor->xport); + + return ret; +} + +int bmkt_sensor_send_message_sync(bmkt_sensor_t *sensor, uint8_t msg_id, uint8_t payload_size, + uint8_t *payload, uint8_t **resp_buf, int *resp_len, bmkt_response_t *resp) +{ + int ret; + uint8_t *cmd; + int cmd_buf_len = 0; + int msg_len; + bmkt_msg_resp_t msg_resp; + + *resp_len = BMKT_MAX_TRANSFER_LEN; + + ret = bmkt_transport_get_command_buffer(&sensor->xport, &cmd, &cmd_buf_len); + if (ret != BMKT_SUCCESS) + { + return BMKT_OUT_OF_MEMORY; + } + + cmd[0] = SENSOR_CMD_ACE_COMMAND; + msg_len = cmd_buf_len - SENSOR_FW_CMD_HEADER_LEN; + + ret = bmkt_compose_message(&cmd[1], &msg_len, msg_id, sensor->seq_num++, payload_size, + payload); + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("Failed to compose ace message: %d\n", ret); + goto cleanup; + } + + ret = bmkt_transport_send_command_sync(&sensor->xport, msg_len + SENSOR_FW_CMD_HEADER_LEN, + resp_buf, resp_len); + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("%s: failed to send ACE command: %d\n", __func__, ret); + goto cleanup; + } + + ret = bmkt_parse_message_header(&(*resp_buf)[2], *resp_len - 2, &msg_resp); + if (ret != BMKT_SUCCESS) + { + goto cleanup; + } + + ret = bmkt_parse_message_payload(&msg_resp, resp); + if (ret != BMKT_SUCCESS) + { + goto cleanup; + } + +cleanup: + ret = bmkt_transport_release_command_buffer(&sensor->xport); + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("%s: failed to release command buffer: %d\n", __func__, ret); + return ret; + } + return ret; +} + +int bmkt_sensor_handle_response(bmkt_sensor_t *sensor, uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp) +{ + int ret; + bmkt_session_ctx_t *session_ctx; + bmkt_response_t resp; + int i; + + sensor->expect_response = 0; + ret = bmkt_parse_message_header(&resp_buf[2], resp_len - 2, msg_resp); + if (ret == BMKT_CORRUPT_MESSAGE) + { + bmkt_warn_log("Corrupt Message Received\n"); + return ret; + } + else if (ret != BMKT_SUCCESS) + { + return ret; + } + +#if 0 // invalid finger event seq num hack!! + if (msg_resp->seq_num == 0) + { +#endif // invalid finger event seq num hack!! + if (msg_resp->msg_id == BMKT_EVT_FINGER_REPORT) + { + // finger event message + bmkt_info_log("Finger event!"); + bmkt_finger_event_t finger_event; + + if (msg_resp->payload_len != 1) + { + return BMKT_UNRECOGNIZED_MESSAGE; + } + + if (msg_resp->payload[0] == 0x01) + { + finger_event.finger_state = BMKT_FINGER_STATE_ON_SENSOR; + } + else + { + finger_event.finger_state = BMKT_FINGER_STATE_NOT_ON_SENSOR; + } + + if (sensor->finger_event_cb != NULL) + { + sensor->finger_event_cb(&finger_event, sensor->finger_cb_ctx); + } + return BMKT_SUCCESS; + } +#if 0 // invalid finger event seq num hack!! + else +#else // invalid finger event seq num hack!! + if (msg_resp->seq_num == 0) + { +#endif // invalid finger event seq num hack!! + if (msg_resp->msg_id == BMKT_RSP_GENERAL_ERROR) + { + // report general error + bmkt_info_log("General Error!\n"); + uint16_t err; + + if (sensor->gen_err_cb != NULL) + { + err = (msg_resp->payload[0] << 8) | msg_resp->payload[1]; + sensor->gen_err_cb(err, sensor->gen_err_cb_ctx); + } + return BMKT_SUCCESS; + } + } + + ret = bmkt_parse_message_payload(msg_resp, &resp); + if (ret != BMKT_SUCCESS) + { + bmkt_warn_log("Failed to process response: %d\n", ret); + return ret; + } + + session_ctx = get_session_ctx(sensor, msg_resp->seq_num); + if (session_ctx == NULL) + { + bmkt_warn_log("Response received with invalid sequence number: %d, return BMKT_UNRECOGNIZED_MESSAGE(112)\n", msg_resp->seq_num); + return BMKT_UNRECOGNIZED_MESSAGE; + } + + if (session_ctx->resp_cb != NULL) + { + ret = session_ctx->resp_cb(&resp, session_ctx->cb_ctx); + if (ret != BMKT_SUCCESS) + { + bmkt_warn_log("response callback failed: %d\n", ret); + } + } + + if (resp.complete == 1) + { + ret = release_session_ctx(sensor, session_ctx); + if (ret != BMKT_SUCCESS) + { + return ret; + } + } + + if (resp.response_id == BMKT_RSP_CANCEL_OP_OK && resp.result == BMKT_SUCCESS) + { + // The previous commands have been canceled. Release all session ctx + for (i = 0; i < BMKT_MAX_PENDING_SESSIONS; i++) + { + release_session_ctx(sensor, &sensor->pending_sessions[i]); + } + } + + return BMKT_SUCCESS; +} + +int bmkt_sensor_handle_interrupt(bmkt_sensor_t *sensor) +{ + int ret = BMKT_SUCCESS; + int mask = 0; + int len = 0; + uint8_t *resp_buf; + int resp_len; + bmkt_msg_resp_t msg_resp; + +#ifdef THREAD_SUPPORT + ret = bmkt_mutex_lock(&sensor->interrupt_mutex); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to lock mutex: %d\n", ret); + return ret; + } +#endif /* THREAD_SUPPORT */ + + for (;;) + { + ret = bmkt_transport_read_interrupt_status(&sensor->xport, &mask); + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("bmkt_sensor_handle_interrupt: bmkt_transport_read_interrupt_status failed with ret=0x%x\n", ret); + goto cleanup; + } + + if (mask == BMKT_XPORT_INT_NONE) + { + ret = BMKT_SUCCESS; + bmkt_dbg_log("bmkt_sensor_handle_interrupt: bmkt_transport_read_interrupt_status get mask=0, ret BMKT_SUCCESS\n"); + goto cleanup; + } + + if (mask & BMKT_XPORT_INT_RESPONSE) + { + ret = bmkt_transport_get_response_buffer(&sensor->xport, &resp_buf, &resp_len); + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("bmkt_sensor_handle_interrupt: bmkt_transport_get_response_buffer failed with ret=0x%x\n", ret); + goto cleanup; + } + ret = bmkt_transport_receive_response(&sensor->xport, &len); + if (ret == BMKT_SUCCESS) + { + ret = bmkt_sensor_handle_response(sensor, resp_buf, resp_len, &msg_resp); + } + bmkt_transport_release_response_buffer(&sensor->xport); + + if (ret != BMKT_SUCCESS) + { + goto cleanup; + } + } + + if (mask & BMKT_XPORT_INT_FINGER) + { + // may not use this + } + + if (mask & BMKT_XPORT_INT_ASYNC) + { + ret = bmkt_sensor_send_async_read_command(sensor); + if (ret != BMKT_SUCCESS) + { + if (ret == BMKT_SENSOR_NOT_READY || ret == BMKT_SENSOR_RESPONSE_PENDING) + { + continue; + } + else + { + goto cleanup; + } + } + } + + break; + } + +cleanup: +#ifdef THREAD_SUPPORT + bmkt_mutex_unlock(&sensor->interrupt_mutex); +#endif /* THREAD_SUPPORT */ + return BMKT_SUCCESS; +} + +int bmkt_sensor_process_pending_interrupts(bmkt_sensor_t *sensor) +{ + int ret; + + if (sensor->sensor_state == BMKT_SENSOR_STATE_UNINIT || + (!(sensor->expect_response) && !(sensor->flags & BMKT_SENSOR_FLAGS_POLLING))) + { + bmkt_event_wait(&sensor->interrupt_event, 0); + } + + ret = bmkt_sensor_handle_interrupt(sensor); + if (ret != BMKT_SUCCESS) + { + bmkt_warn_log("bmkt_sensor_process_pending_interrupts: Failed to handle interrupt: %d\n", ret); + return ret; + } + + return BMKT_SUCCESS; +} + +int bmkt_register_finger_event_notification(bmkt_sensor_t *sensor, bmkt_event_cb_t cb, void *cb_ctx) +{ + if (sensor == NULL || cb == NULL) + { + return BMKT_INVALID_PARAM; + } + + sensor->finger_event_cb = cb; + sensor->finger_cb_ctx = cb_ctx; + + return BMKT_SUCCESS; +} diff --git a/libfprint/drivers/synaptics/src/synaptics.c b/libfprint/drivers/synaptics/src/synaptics.c new file mode 100644 index 0000000..4122560 --- /dev/null +++ b/libfprint/drivers/synaptics/src/synaptics.c @@ -0,0 +1,665 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 "synaptics" + +#include "drivers_api.h" +#include "fpi-async.h" +#include "fp_internal.h" + +#include "synaptics.h" + + +static const struct usb_id id_table[] = { + { .vendor = SYNAPTICS_VENDOR_ID, .product = SYNAPTICS_PRODUCT_ID_A9, }, + + { 0, 0, 0, }, /* terminating entry */ +}; + +#define SYNA_ASSERT(_state, _message, _err) ({ \ + if (__builtin_expect(!(_state), 0)) \ + { \ + fp_err("%s",(_message)); \ + result = (_err); \ + goto cleanup; \ + } \ +}) + +static int general_error_callback(uint16_t error, void *ctx) +{ + fp_err("Received General Error %d from the sensor", error); + return 0; +} + +static int finger_event_callback(bmkt_finger_event_t *event, void *ctx) +{ + struct fp_dev *dev=(struct fp_dev *)ctx; + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + + switch (event->finger_state) + { + case BMKT_FINGER_STATE_UNKNOWN: + fp_info("Finger state is not known"); + break; + case BMKT_FINGER_STATE_ON_SENSOR: + sdev->isFingerOnSensor = TRUE; + fp_info("Finger in on the sensor"); + break; + case BMKT_FINGER_STATE_NOT_ON_SENSOR: + sdev->isFingerOnSensor = FALSE; + fp_info("Finger is not on the sensor"); + if(sdev->state == SYNA_STATE_VERIFY_DELAY_RESULT) + { + fp_info("verify no match"); + fpi_drvcb_report_verify_result(dev, FP_VERIFY_NO_MATCH, NULL); + } + break; + } + + return BMKT_SUCCESS; +} + +static int cancel_resp(bmkt_response_t *resp, void *ctx) +{ + + switch (resp->response_id) + { + case BMKT_RSP_CANCEL_OP_OK: + fp_info("Successfully canceled operation"); + break; + case BMKT_RSP_CANCEL_OP_FAIL: + fp_info("Failed to cancel current operation: %d", resp->result); + break; + } + + return 0; +} + + +struct syna_mis_print_data +{ + uint8_t finger_id; + uint8_t user_id[BMKT_MAX_USER_ID_LEN]; +}; + +static int enroll_response(bmkt_response_t *resp, void *ctx) +{ + bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp; + struct fp_dev *dev=(struct fp_dev *)ctx; + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + + switch (resp->response_id) + { + case BMKT_RSP_ENROLL_READY: + { + fpi_drvcb_enroll_started(dev, 0); + sdev->enroll_resp_data.progress = 0; + fp_info("Place Finger on the Sensor!"); + break; + } + case BMKT_RSP_CAPTURE_COMPLETE: + { + fp_info("Fingerprint image capture complete!"); + break; + } + case BMKT_RSP_ENROLL_REPORT: + { + fp_info("Enrollment is %d %% ", enroll_resp->progress); + if(enroll_resp->progress < 100) + { + if(sdev->enroll_resp_data.progress == enroll_resp->progress) + fpi_drvcb_enroll_stage_completed(dev, FP_ENROLL_RETRY, NULL, NULL); + else + fpi_drvcb_enroll_stage_completed(dev, FP_ENROLL_PASS, NULL, NULL); + } + sdev->enroll_resp_data.progress = enroll_resp->progress; + break; + } + case BMKT_RSP_ENROLL_PAUSED: + { + fp_info("Enrollment has been paused!"); + break; + } + case BMKT_RSP_ENROLL_RESUMED: + { + fp_info("Enrollment has been resumed!"); + break; + } + case BMKT_RSP_ENROLL_FAIL: + { + fp_info("Enrollment has failed!: %d", resp->result); + break; + } + case BMKT_RSP_ENROLL_OK: + { + struct syna_mis_print_data mis_data; + struct fp_print_data *fdata = NULL; + struct fp_print_data_item *item = NULL; + fdata = fpi_print_data_new(dev); + item = fpi_print_data_item_new(sizeof(mis_data)); + fp_info("Enrollment was successful!"); + mis_data.finger_id = enroll_resp->finger_id; + memcpy(mis_data.user_id, enroll_resp->user_id, + BMKT_MAX_USER_ID_LEN); + memcpy(item->data, &mis_data, + sizeof(struct syna_mis_print_data)); + fdata->prints = g_slist_prepend(fdata->prints, item); + fpi_drvcb_enroll_stage_completed(dev, 1, fdata, NULL); + break; + } + } + return 0; +} + +static int dev_init(struct fp_dev *dev, unsigned long driver_data) +{ + synaptics_dev *sdev = NULL; + int result = 0, ret = 0; + struct libusb_device_descriptor dsc; + libusb_device *udev = libusb_get_device(fpi_dev_get_usb_dev(dev)); + + fp_info("%s ", __func__); + + /* Set enroll stage number */ + fpi_dev_set_nr_enroll_stages(dev, ENROLL_SAMPLES); + + /* Initialize private structure */ + sdev = g_malloc0(sizeof(synaptics_dev)); + sdev->sensor_desc.xport_type = BMKT_TRANSPORT_TYPE_USB; + sdev->usb_config = &sdev->sensor_desc.xport_config.usb_config; + + result = libusb_get_device_descriptor(udev, &dsc); + if(result) + { + fp_err("Failed to get device descriptor"); + return -1; + } + sdev->usb_config->product_id = dsc.idProduct; + + pthread_mutex_init(&sdev->op_mutex, NULL); + pthread_cond_init(&sdev->op_cond, NULL); + + result = bmkt_init(&(sdev->ctx)); + if (result != BMKT_SUCCESS) + { + fp_err("Failed to initialize bmkt context: %d", result); + return -1; + } + fp_info("bmkt_init successfully."); + + result = bmkt_open(sdev->ctx, &sdev->sensor_desc, &sdev->sensor, general_error_callback, NULL); + if (result != BMKT_SUCCESS) + { + fp_err("Failed to open bmkt sensor: %d", result); + goto bmkt_cleanup; + } + + result = bmkt_register_finger_event_notification(sdev->sensor, finger_event_callback, dev); + if (result != BMKT_SUCCESS) + { + fp_err("Failed to register finger event notification: %d", result); + goto bmkt_cleanup; + } + result = bmkt_init_fps(sdev->sensor); + if (result == BMKT_SUCCESS) + { + fp_info("Successfully initialized the FPS"); + } + else if (result == BMKT_OPERATION_DENIED) + { + /* sensor already intialized...allow operations to continue */ + fp_info("FPS already initialized"); + result = BMKT_SUCCESS; + } + else + { + fp_err("Failed to initialize the FPS: %d", result); + goto bmkt_cleanup; + } + + fp_dev_set_instance_data(dev, sdev); + /* Notify open complete */ + fpi_drvcb_open_complete(dev, 0); + return result; + +bmkt_cleanup: + ret = bmkt_close(sdev->sensor); + if (ret != BMKT_SUCCESS) + { + fp_err("Failed to close bmkt sensor: %d", ret); + goto cleanup; + } + bmkt_exit(sdev->ctx); + g_free(sdev); + +cleanup: + fpi_drvcb_open_complete(dev, 1); + return result; +} +static void dev_exit(struct fp_dev *dev) +{ + int ret = 0; + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + ret = bmkt_close(sdev->sensor); + if (ret != BMKT_SUCCESS) + { + fp_err("Failed to close bmkt sensor: %d", ret); + return; + } + + bmkt_exit(sdev->ctx); + + ret = pthread_mutex_destroy(&sdev->op_mutex); + if (ret) + { + fp_err("failed to destroy mutex"); + } + + ret = pthread_cond_destroy(&sdev->op_cond); + if (ret) + { + fp_err("failed to destroy cond "); + } + + g_free(sdev); + fpi_drvcb_close_complete(dev); +} + +static gboolean rand_string(char *str, size_t size) +{ + const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + srand(time(NULL)); + if (size) { + --size; + for (size_t n = 0; n < size; n++) { + int key = rand() % (int) (sizeof charset - 1); + str[n] = charset[key]; + } + str[size] = '\0'; + } + else + return FALSE; + return TRUE; +} + +#define TEMPLATE_ID_SIZE 20 + +void get_file_data(struct fp_dev *dev, const char *basepath) +{ + char path[PATH_MAX]; + struct dirent *dp; + DIR *dir = opendir(basepath); + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + if(!dir) + return; + while( (dp = readdir(dir)) != NULL) + { + if(strcmp(dp->d_name, ".")!=0 && strcmp(dp->d_name,"..")!=0) + { + strcpy(path,basepath); + strcat(path,"/"); + strcat(path,dp->d_name); + fp_info("%s type is %d ",dp->d_name,dp->d_type); + if(dp->d_type == DT_REG) + { + gsize length; + gchar *contents; + GError *err = NULL; + struct fp_print_data *fdata; + fp_info(" load file %s ", path); + g_file_get_contents(path, &contents, &length, &err); + if (err) { + fp_err("load file failed "); + } + else + { + fdata = fp_print_data_from_data(contents, length); + struct fp_print_data_item *item = fdata->prints->data; + struct syna_mis_print_data *print_data =(struct syna_mis_print_data *) item -> data; + + char *data_node=(char *)g_malloc0(strlen(print_data->user_id) + 1); + memcpy(data_node, print_data->user_id, strlen(print_data->user_id) + 1); + sdev->file_gslist = g_slist_append(sdev->file_gslist, data_node); + g_free(contents); + } + } + else + get_file_data(dev, path); + } + } +} + +static int get_enrolled_users_resp(bmkt_response_t *resp, void *ctx) +{ + + bmkt_enroll_templates_resp_t *get_enroll_templates_resp = &resp->response.enroll_templates_resp; + struct fp_dev *dev=(struct fp_dev *)ctx; + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + + switch (resp->response_id) + { + case BMKT_RSP_QUERY_FAIL: + fp_info("Failed to query enrolled users: %d", resp->result); + pthread_mutex_lock(&sdev->op_mutex); + sdev->op_finished = 1; + pthread_cond_signal(&sdev->op_cond); + pthread_mutex_unlock(&sdev->op_mutex); + break; + case BMKT_RSP_QUERY_RESPONSE_COMPLETE: + pthread_mutex_lock(&sdev->op_mutex); + sdev->op_finished = 1; + pthread_cond_signal(&sdev->op_cond); + pthread_mutex_unlock(&sdev->op_mutex); + fp_info("Query complete!"); + break; + case BMKT_RSP_TEMPLATE_RECORDS_REPORT: + + for (int n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++) + { + if (get_enroll_templates_resp->templates[n].user_id_len == 0) + continue; + + fp_info("![query %d of %d] template %d: status=0x%x, userId=%s, fingerId=%d", + get_enroll_templates_resp->query_sequence, + get_enroll_templates_resp->total_query_messages, + n, + get_enroll_templates_resp->templates[n].template_status, + get_enroll_templates_resp->templates[n].user_id, + get_enroll_templates_resp->templates[n].finger_id); + char *data_node = (char *)g_malloc0(strlen(get_enroll_templates_resp->templates[n].user_id) + 1); + memcpy(data_node, get_enroll_templates_resp->templates[n].user_id, + strlen(get_enroll_templates_resp->templates[n].user_id) + 1 ); + sdev->sensor_gslist = g_slist_prepend(sdev->sensor_gslist, data_node); + } + break; + } + + return 0; +} + +void get_sensor_data(struct fp_dev *dev) +{ + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + int result; + sdev->op_finished = 0; + result = bmkt_get_enrolled_users(sdev->sensor, get_enrolled_users_resp, dev); + if (result != BMKT_SUCCESS) + { + fp_err("Failed to get enrolled users: %d", result); + } + else + { + fp_info("get enrolled data started."); + } + pthread_mutex_lock(&sdev->op_mutex); + if(sdev->op_finished == 0) + { + pthread_cond_wait(&sdev->op_cond, &sdev->op_mutex); + } + pthread_mutex_unlock(&sdev->op_mutex); +} + +static int del_enrolled_user_resp(bmkt_response_t *resp, void *ctx) +{ + bmkt_del_user_resp_t *del_user_resp = &resp->response.del_user_resp; + struct fp_dev *dev=(struct fp_dev *)ctx; + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + + switch (resp->response_id) + { + case BMKT_RSP_DELETE_PROGRESS: + fp_info("Deleting Enrolled Users is %d%% complete", + del_user_resp->progress); + break; + case BMKT_RSP_DEL_USER_FP_FAIL: + fp_info("Failed to delete enrolled user: %d", resp->result); + pthread_mutex_lock(&sdev->op_mutex); + sdev->op_finished = 1; + pthread_cond_signal(&sdev->op_cond); + pthread_mutex_unlock(&sdev->op_mutex); + break; + case BMKT_RSP_DEL_USER_FP_OK: + fp_info("Successfully deleted enrolled user"); + pthread_mutex_lock(&sdev->op_mutex); + sdev->op_finished = 1; + pthread_cond_signal(&sdev->op_cond); + pthread_mutex_unlock(&sdev->op_mutex); + break; + } + return 0; +} + + +const char FPRINTD_DATAPATH[]="/usr/local/var/lib/fprint"; +/* + * Delete the data which doesn't exist in fprintd folder from sensor database, + * otherwise, new finger may have problem to be recognized if it + * already exists in sensor. +*/ +void sync_database(struct fp_dev *dev) +{ + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + int result = 0; + int sindex, findex; + GSList* snode; + GSList* fnode; + + get_file_data(dev, FPRINTD_DATAPATH); + get_sensor_data(dev); + + for(sindex = 0; (snode = g_slist_nth(sdev->sensor_gslist, sindex)); sindex++) + { + for(findex = 0; (fnode = g_slist_nth(sdev->file_gslist, findex)); findex++) + { + if(strlen(snode->data) == strlen(fnode->data) && + strncmp(snode->data, fnode->data, strlen(snode->data)) == 0) + { + break; + } + } + if(!fnode) + { + sdev->op_finished = 0; + result = bmkt_delete_enrolled_user(sdev->sensor, 1, snode->data, + strlen(snode->data), del_enrolled_user_resp, dev); + if (result != BMKT_SUCCESS) + { + fp_err("Failed to delete enrolled user: %d", result); + } + else + { + + pthread_mutex_lock(&sdev->op_mutex); + if(sdev->op_finished == 0) + { + pthread_cond_wait(&sdev->op_cond, &sdev->op_mutex); + } + pthread_mutex_unlock(&sdev->op_mutex); + + } + + } + } + + g_slist_free(sdev->file_gslist); + g_slist_free(sdev->sensor_gslist); +} +static int enroll_start(struct fp_dev *dev) +{ + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + int result = 0; + char userid[TEMPLATE_ID_SIZE + 1]; + + sync_database(dev); + + fp_info("enroll_start"); + + + rand_string(userid, TEMPLATE_ID_SIZE); + + int useridlength =0; + int finger_id; + + finger_id = 1; + useridlength = strlen(userid); + + sdev->state = SYNA_STATE_ENROLL; + + result = bmkt_enroll(sdev->sensor, userid, useridlength, + finger_id, enroll_response, dev); + if (result) + { + fp_err("Failed to enroll finger: %d", result); + } + + return 0; +} + + +static int enroll_stop(struct fp_dev *dev) +{ + fp_info("syna enroll stop"); + int ret; + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + sdev->state = SYNA_STATE_IDLE; + ret = bmkt_cancel_op(sdev->sensor, cancel_resp, dev); + if (ret != BMKT_SUCCESS) + { + fp_err("Failed to cancel operation: %d", ret); + } + fpi_drvcb_enroll_stopped(dev); + return 1; +} + +static int verify_response(bmkt_response_t *resp, void *ctx) +{ + bmkt_verify_resp_t *verify_resp = &resp->response.verify_resp; + struct fp_dev *dev=(struct fp_dev *)ctx; + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + + switch (resp->response_id) + { + case BMKT_RSP_VERIFY_READY: + { + fp_info("Place Finger on the Sensor!"); + fpi_drvcb_verify_started(dev, 0); + break; + } + case BMKT_RSP_CAPTURE_COMPLETE: + { + fp_info("Fingerprint image capture complete!"); + break; + } + case BMKT_RSP_VERIFY_FAIL: + { + fp_err("Verify has failed!: %d", resp->result); + if(resp->result == BMKT_SENSOR_STIMULUS_ERROR || resp->result == BMKT_FP_NO_MATCH) + { + sdev->state = SYNA_STATE_VERIFY_DELAY_RESULT; + } + else + fpi_drvcb_report_verify_result(dev, FP_VERIFY_NO_MATCH, NULL); + break; + } + case BMKT_RSP_VERIFY_OK: + { + fp_info("Verify was successful! for user: %s finger: %d score: %f", + verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result); + fpi_drvcb_report_verify_result(dev, FP_VERIFY_MATCH, NULL); + break; + } + } + + return 0; +} + +static int verify_start(struct fp_dev *dev) +{ + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + int result = 0; + struct fp_print_data *print = fpi_dev_get_verify_data(dev);; + struct fp_print_data_item *item = print->prints->data; + struct syna_mis_print_data *print_data; + bmkt_user_id_t user; + + if(item->length != sizeof(struct syna_mis_print_data)) + { + fp_err("print data is incorrect !"); + goto cleanup; + } + + print_data = (struct syna_mis_print_data *)item->data; + + memset(&user, 0, sizeof(bmkt_user_id_t)); + memcpy(user.user_id, print_data->user_id, sizeof(print_data->user_id)); + + fp_info("syna verify_start !"); + + user.user_id_len = strlen(user.user_id); + if (user.user_id_len <= 0 || user.user_id[0] == ' ') + { + fp_err("Invalid user name."); + goto cleanup; + } + + sdev->state = SYNA_STATE_VERIFY; + result = bmkt_verify(sdev->sensor, &user, verify_response, dev); + if (result != BMKT_SUCCESS) + { + fp_err("Failed to verify finger: %d", result); + } + + return 0; + +cleanup: + fpi_drvcb_verify_started(dev, 1); + return -1; +} + +static int verify_stop(struct fp_dev *dev, gboolean iterating) +{ + fp_info("syna verify_stop"); + int ret; + synaptics_dev *sdev = FP_INSTANCE_DATA(dev); + sdev->state = SYNA_STATE_IDLE; + ret = bmkt_cancel_op(sdev->sensor, cancel_resp, dev); + if (ret != BMKT_SUCCESS) + { + fp_err("Failed to cancel operation: %d", ret); + } + fpi_drvcb_verify_stopped(dev); + return 0; +} + +struct fp_driver synaptics_driver = { + .id = SYNAPTICS_ID, + .name = FP_COMPONENT, + .full_name = SYNAPTICS_DRIVER_FULLNAME, + .id_table = id_table, + .scan_type = FP_SCAN_TYPE_PRESS, + .open = dev_init, + .close = dev_exit, + .enroll_start = enroll_start, + .enroll_stop = enroll_stop, + .verify_start = verify_start, + .verify_stop = verify_stop, +}; + + + + diff --git a/libfprint/drivers/synaptics/src/transport/transport.c b/libfprint/drivers/synaptics/src/transport/transport.c new file mode 100644 index 0000000..c5b258c --- /dev/null +++ b/libfprint/drivers/synaptics/src/transport/transport.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#include "bmkt_internal.h" +#include "transport.h" +#include "bmkt_message.h" +#include "crc.h" + +#define BMKT_VCSFW_COMMAND_LEN 1 + +extern const bmkt_transport_drv_t usb_xport_drv; + +int bmkt_transport_open(bmkt_transport_t *xport, bmkt_transport_type_t xport_type, + const bmkt_transport_config_t *config, bmkt_sensor_t *sensor) +{ + int ret; + + xport->xport_type = xport_type; + switch (xport->xport_type) + { + case BMKT_TRANSPORT_TYPE_USB: + xport->drv = &usb_xport_drv; + break; + break; + } + + xport->sensor = sensor; + +#ifdef THREAD_SUPPORT + ret = bmkt_mutex_init(&xport->transfer_buffer_mutex); + if (ret != BMKT_SUCCESS) + { + return ret; + } +#endif + + return xport->drv->open(xport, config); +} + +int bmkt_transport_close(bmkt_transport_t *xport) +{ +#ifdef THREAD_SUPPORT + bmkt_mutex_destroy(&xport->transfer_buffer_mutex); +#endif + return xport->drv->close(xport); +} + +int bmkt_transport_get_command_buffer(bmkt_transport_t *xport, uint8_t **buf, int *len) +{ +#ifdef THREAD_SUPPORT + int ret; + + ret = bmkt_mutex_lock(&xport->transfer_buffer_mutex); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to lock mutex: %d\n", ret); + return ret; + } +#endif /* THREAD_SUPPORT */ + return xport->drv->get_command_buffer(xport, buf, len); +} + +int bmkt_transport_release_command_buffer(bmkt_transport_t *xport) +{ +#ifdef THREAD_SUPPORT + int ret; + + ret = bmkt_mutex_unlock(&xport->transfer_buffer_mutex); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to release mutex: %d\n", ret); + return ret; + } +#endif /* THREAD_SUPPORT */ + + return BMKT_SUCCESS; +} + +int bmkt_transport_get_response_buffer(bmkt_transport_t *xport, uint8_t **resp, int *len) +{ +#ifdef THREAD_SUPPORT + int ret; + + ret = bmkt_mutex_lock(&xport->transfer_buffer_mutex); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to lock mutex: %d\n", ret); + return ret; + } +#endif /* THREAD_SUPPORT */ + return xport->drv->get_response_buffer(xport, resp, len); +} + +int bmkt_transport_release_response_buffer(bmkt_transport_t *xport) +{ +#ifdef THREAD_SUPPORT + int ret; + + ret = bmkt_mutex_unlock(&xport->transfer_buffer_mutex); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to unlock mutex: %d\n", ret); + return ret; + } +#endif /* THREAD_SUPPORT */ + + return BMKT_SUCCESS; +} + +int bmkt_transport_send_command(bmkt_transport_t *xport, int len) +{ + return xport->drv->send_command(xport, len); +} + +int bmkt_transport_send_command_sync(bmkt_transport_t *xport, int len, uint8_t **resp_buf, + int *resp_len) +{ + return xport->drv->send_command_sync(xport, len, resp_buf, resp_len); +} + +int bmkt_transport_receive_response(bmkt_transport_t *xport, int *len) +{ + return xport->drv->receive_response(xport, len); +} + +int bmkt_transport_read_interrupt_status(bmkt_transport_t *xport, int *interupt_mask) +{ + return xport->drv->read_interrupt_status(xport, interupt_mask); +} \ No newline at end of file diff --git a/libfprint/drivers/synaptics/src/transport/usb_transport.c b/libfprint/drivers/synaptics/src/transport/usb_transport.c new file mode 100644 index 0000000..e1794e2 --- /dev/null +++ b/libfprint/drivers/synaptics/src/transport/usb_transport.c @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + + +#include "bmkt_internal.h" +#include "transport.h" +#include "usb_transport.h" +#include "sensor.h" + +#define USB_ASYNC_MESSAGE_PENDING 0x4 + +#ifdef WIN32 +static void WINAPI usb_xfer_callback(struct libusb_transfer *transfer) +#else +static void usb_xfer_callback(struct libusb_transfer *transfer) +#endif /* WIN32 */ +{ + bmkt_transport_t *xport = (bmkt_transport_t *)transfer->user_data; + bmkt_usb_transport_t *usb_xport = &xport->xport_data.usb_xport; + +#ifdef TRANSPORT_DEBUG + bmkt_dbg_log("INTERRUPT: (%d) ", transfer->actual_length); + print_buffer(transfer->buffer, transfer->actual_length); +#endif + + usb_xport->interrupt_mask = BMKT_XPORT_INT_NONE; + + if (transfer->buffer[5] & USB_ASYNC_MESSAGE_PENDING) + { + usb_xport->interrupt_mask |= BMKT_XPORT_INT_ASYNC; + } + + //always send async read for now. + usb_xport->interrupt_mask |= BMKT_XPORT_INT_ASYNC; + + bmkt_event_set(&xport->sensor->interrupt_event); + + libusb_submit_transfer(transfer); +} + +#ifdef WIN32 +static DWORD WINAPI usb_interrupt_thread(LPVOID ctx) +#else +static void *usb_interrupt_thread(void *ctx) +#endif +{ + int ret; + bmkt_transport_t *xport = (bmkt_transport_t *)ctx; + bmkt_usb_transport_t *usb_xport = &xport->xport_data.usb_xport; + struct libusb_transfer *interrupt_xfer; + + interrupt_xfer = libusb_alloc_transfer(0); + if (interrupt_xfer == NULL) + { + return (void *)BMKT_GENERAL_ERROR; + } + + libusb_fill_interrupt_transfer(interrupt_xfer, usb_xport->handle, USB_EP_INTERRUPT, + usb_xport->interrupt_data, sizeof(usb_xport->interrupt_data), usb_xfer_callback, xport, 0); + + ret = libusb_submit_transfer(interrupt_xfer); + if (ret != LIBUSB_SUCCESS) + { + libusb_free_transfer(interrupt_xfer); + if (ret == LIBUSB_ERROR_NO_DEVICE) + { + return (void *)BMKT_SENSOR_MALFUNCTION; + } + else + { + return (void *)BMKT_GENERAL_ERROR; + } + } + + for (;;) + { + ret = libusb_handle_events_completed(usb_xport->ctx, &usb_xport->completed); + if (ret) + { + if (ret == LIBUSB_ERROR_INTERRUPTED) + { + continue; + } + bmkt_err_log("Failed to handle event timeout: %d\n", ret); + } + if(usb_xport->completed) + { + bmkt_err_log("interrupt thread going to terminated. \n"); + break; + } + } + + libusb_free_transfer(interrupt_xfer); + + return (void *)BMKT_SUCCESS; +} + +static int find_fps_device(bmkt_usb_transport_t *usb_xport, const bmkt_usb_config_t *usb_config) +{ + int ret = BMKT_GENERAL_ERROR; + int count; + int i; + libusb_device **devs; + struct libusb_device_descriptor desc; + + count = libusb_get_device_list(usb_xport->ctx, &devs); + if (count < 0) + { + return ret; + } + + for (i = 0; i < count; i++) + { + ret = libusb_get_device_descriptor(devs[i], &desc); + if (ret < 0) + { + ret = BMKT_GENERAL_ERROR; + goto cleanup; + } + + if (desc.idVendor != 0x06CB) + { + continue; + } + + if (desc.idProduct != usb_config->product_id) + { + continue; + } + + // Add additional checks to make sure we have the right FPS? + usb_xport->device = libusb_ref_device(devs[i]); + + ret = BMKT_SUCCESS; + break; + } + +cleanup: + libusb_free_device_list(devs, 1); + return ret; +} + +static int usb_open(bmkt_transport_t *xport, const bmkt_transport_config_t *xport_config) +{ + int ret; + bmkt_usb_transport_t *usb_xport = &xport->xport_data.usb_xport; + xport->xport_config.usb_config = xport_config->usb_config; + bmkt_usb_config_t *usb_config = &xport->xport_config.usb_config; + struct libusb_config_descriptor *configDesc; + const struct libusb_interface *iface; + const struct libusb_interface_descriptor *ifaceDesc; + const struct libusb_endpoint_descriptor *endpointDesc; + int config; + int i; + usb_xport->completed = 0; + ret = libusb_init(&usb_xport->ctx); + if (ret) + { + return BMKT_GENERAL_ERROR; + } + + ret = find_fps_device(usb_xport, usb_config); + if (ret != BMKT_SUCCESS) + { + return ret; + } + + if (usb_xport->device == NULL) + { + return BMKT_GENERAL_ERROR; + } + + ret = libusb_open(usb_xport->device, &usb_xport->handle); + if (ret) + { + return BMKT_SENSOR_MALFUNCTION; + } + + ret = libusb_reset_device(usb_xport->handle); + if (ret) + { + bmkt_dbg_log("Failed to reset device\n"); + } + + ret = libusb_get_config_descriptor(usb_xport->device, USB_DEFAULT_CONFIGURATION, &configDesc); + if (ret) + { + ret = BMKT_SENSOR_MALFUNCTION; + goto close_handle; + } + + ret = libusb_get_configuration(usb_xport->handle, &config); + if (ret) + { + ret = BMKT_SENSOR_MALFUNCTION; + goto free_config; + } + + if (configDesc->bConfigurationValue != config) + { + ret = libusb_set_configuration(usb_xport->handle, config); + if (ret) + { + ret = BMKT_SENSOR_MALFUNCTION; + goto free_config; + } + } + + ret = libusb_kernel_driver_active(usb_xport->handle, 0); + if (ret == 1) + { + bmkt_err_log("Failed to detect kernel driver\n"); + ret = BMKT_SENSOR_MALFUNCTION; + goto free_config; + } + + ret = libusb_claim_interface(usb_xport->handle, USB_DEFAULT_INTERFACE); + if (ret) + { + ret = BMKT_SENSOR_MALFUNCTION; + goto free_config; + } + + iface = configDesc->interface + USB_DEFAULT_INTERFACE; + ifaceDesc = iface->altsetting + USB_DEFAULT_ALT_SETTING; + endpointDesc = ifaceDesc->endpoint; + + for (i = 0; i < ifaceDesc->bNumEndpoints; i++) + { + ret = libusb_clear_halt(usb_xport->handle, endpointDesc->bEndpointAddress); + if (ret) + { + ret = BMKT_SENSOR_MALFUNCTION; + goto free_config; + } + ++endpointDesc; + } + + ret = bmkt_event_init(&xport->sensor->interrupt_event); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to initialize interrupt event: %d\n", ret); + return ret; + } + + ret = bmkt_thread_create(&usb_xport->interrupt_thread, usb_interrupt_thread, xport); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to create interrupt thread: %d\n", ret); + return ret; + } + +free_config: + libusb_free_config_descriptor(configDesc); +close_handle: + if (ret) + { + libusb_close(usb_xport->handle); + } + + return ret; +} + +static int usb_close(bmkt_transport_t *xport) +{ + int ret; + bmkt_usb_transport_t *usb_xport = &xport->xport_data.usb_xport; + usb_xport->completed = 1; + //set completed to 1 instead of thread destroy + + ret = bmkt_event_destroy(&xport->sensor->interrupt_event); + if (ret != BMKT_SUCCESS) + { + bmkt_err_log("Failed to initialize interrupt event: %d\n", ret); + return ret; + } + + if (usb_xport->handle) + { + libusb_release_interface(usb_xport->handle, USB_DEFAULT_INTERFACE); + libusb_close(usb_xport->handle); + } + libusb_exit(usb_xport->ctx); + + return BMKT_SUCCESS; +} + +static int bulk_transfer(bmkt_usb_transport_t *usb_xport, uint8_t *buf, int size, uint8_t endpoint, + int *transferred, uint32_t timeout) +{ + int ret; + +#ifdef TRANSPORT_DEBUG + if (!(endpoint & 0x80)) + { + bmkt_dbg_log("TX: (%d) ", size); + print_buffer(buf, size); + } +#endif + + ret = libusb_bulk_transfer(usb_xport->handle, endpoint, buf, size, transferred, timeout); + if (ret) + { + bmkt_warn_log("libusb_bulk_transfer: bulk transfer failed: %d\n", ret); + if (ret == LIBUSB_ERROR_TIMEOUT) + { + return BMKT_OP_TIME_OUT; + } + else + { + return BMKT_SENSOR_MALFUNCTION; + } + } + bmkt_dbg_log("transferred: %d\n", *transferred); + +#ifdef TRANSPORT_DEBUG + if (endpoint & 0x80) + { + bmkt_dbg_log("RX: (%d) ", *transferred); + print_buffer(buf, *transferred); + } +#endif + + return BMKT_SUCCESS; +} + +static int usb_send_command(bmkt_transport_t *xport, int len) +{ + int ret; + int tx_len = 0; + bmkt_usb_transport_t *usb_xport = &xport->xport_data.usb_xport; + + ret = bulk_transfer(usb_xport, xport->transfer, len, USB_EP_REQUEST, &tx_len, 0); + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("Failed to send usb command\n"); + return ret; + } + + usb_xport->interrupt_mask = BMKT_XPORT_INT_RESPONSE; + bmkt_event_set(&xport->sensor->interrupt_event); + + return BMKT_SUCCESS; +} + +static int usb_get_command_buffer(bmkt_transport_t *xport, uint8_t **cmd, int *len) +{ + *len = BMKT_MAX_TRANSFER_LEN; + *cmd = xport->transfer; + + return BMKT_SUCCESS; +} + +static int usb_get_response_buffer(bmkt_transport_t *xport, uint8_t **resp, int *len) +{ + *len = BMKT_MAX_TRANSFER_LEN; + *resp = xport->transfer; + + return BMKT_SUCCESS; +} + +static int usb_receive_resp(bmkt_transport_t *xport, int *len) +{ + int ret; + bmkt_usb_transport_t *usb_xport = &xport->xport_data.usb_xport; + + *len = BMKT_MAX_TRANSFER_LEN; + + // Check to make sure the buffer is clear + memset(xport->transfer, 0, BMKT_MAX_TRANSFER_LEN); + + ret = bulk_transfer(usb_xport, xport->transfer, *len, USB_EP_REPLY, len, 0); + + usb_xport->interrupt_mask &= ~BMKT_XPORT_INT_RESPONSE; + + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("Failed to send usb command\n"); + return ret; + } + + return BMKT_SUCCESS; +} + +static int usb_send_command_sync(bmkt_transport_t *xport, int len, uint8_t **resp_buf, + int *resp_len) +{ + int ret; + int tx_len = 0; + bmkt_usb_transport_t *usb_xport = &xport->xport_data.usb_xport; + + ret = bulk_transfer(usb_xport, xport->transfer, len, USB_EP_REQUEST, &tx_len, 0); + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("Failed to send usb command\n"); + return ret; + } + + // Check to make sure the buffer is clear + memset(xport->transfer, 0, BMKT_MAX_TRANSFER_LEN); + + ret = bulk_transfer(usb_xport, xport->transfer, *resp_len, USB_EP_REPLY, resp_len, 0); + if (ret != BMKT_SUCCESS) + { + bmkt_dbg_log("Failed to send usb command\n"); + return ret; + } + + *resp_buf = xport->transfer; + + return BMKT_SUCCESS; +} + +static int usb_reset(bmkt_transport_t *xport) +{ + return BMKT_OPERATION_DENIED; +} + +static int usb_read_interrupt_status(bmkt_transport_t *xport, int *interrupt_mask) +{ + bmkt_usb_transport_t *usb_xport = &xport->xport_data.usb_xport; + + *interrupt_mask = usb_xport->interrupt_mask; + + return BMKT_SUCCESS; +} + +const bmkt_transport_drv_t usb_xport_drv = { + .open = usb_open, + .close = usb_close, + .send_command = usb_send_command, + .send_command_sync = usb_send_command_sync, + .receive_response = usb_receive_resp, + .get_command_buffer = usb_get_command_buffer, + .get_response_buffer = usb_get_response_buffer, + .reset = usb_reset, + .read_interrupt_status = usb_read_interrupt_status, +}; diff --git a/libfprint/drivers/synaptics/src/util.c b/libfprint/drivers/synaptics/src/util.c new file mode 100644 index 0000000..b8c9324 --- /dev/null +++ b/libfprint/drivers/synaptics/src/util.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2019 Synaptics Inc + * + * 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 + */ + +#include "bmkt_internal.h" + +void print_buffer(uint8_t *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) + { + bmkt_dbg_log("0x%02x ", buf[i]); + if ((i % 16) == 15) + { + bmkt_dbg_log("\n"); + } + } + bmkt_dbg_log("\n"); +} + +static uint64_t extractN(const uint8_t *buf, int len, int *offset, bmkt_byte_order_t byte_order) +{ + int i; + int shift = 0; + int ret = 0; + int off = 0; + + if (offset) + { + off = *offset; + } + + if (len > 8) + { + len = 8; + } + + if (byte_order == BYTE_ORDER_LITTLE) { + for (i = 0; i < len; i++, shift += 8) + { + ret |= (buf[off + i] << shift); + } + } else { + for (i = len - 1; i >= 0; i--, shift += 8) + { + ret |= (buf[off + i] << shift); + } + } + + if (offset) + { + *offset += len; + } + + return ret; +} + +uint32_t extract32(const uint8_t *buf, int *offset, bmkt_byte_order_t byte_order) +{ + return extractN(buf, 4, offset, byte_order); +} + +uint16_t extract16(const uint8_t *buf, int *offset, bmkt_byte_order_t byte_order) +{ + return extractN(buf, 2, offset, byte_order); +} + +uint8_t extract8(const uint8_t *buf, int *offset, bmkt_byte_order_t byte_order) +{ + return extractN(buf, 1, offset, byte_order); +} + +static void encodeN(uint64_t value, int len, uint8_t *buf, int *offset, bmkt_byte_order_t byte_order) +{ + int i; + int shift = 0; + int off = 0; + + if (offset) + { + off = *offset; + } + + if (len > 8) + { + len = 8; + } + + if (byte_order == BYTE_ORDER_LITTLE) + { + for (i = 0; i < len; i++, shift += 8) + { + buf[off + i] = (value >> shift) & 0xFF; + } + } else { + for (i = len - 1; i >= 0; i--, shift += 8) + { + buf[off + i] = (value >> shift) & 0xFF; + } + } + + if (offset) + { + *offset += len; + } +} + +void encode32(uint32_t value, uint8_t *buf, int *offset, bmkt_byte_order_t byte_order) +{ + encodeN(value, 4, buf, offset, byte_order); +} + +void encode16(uint16_t value, uint8_t *buf, int *offset, bmkt_byte_order_t byte_order) +{ + encodeN(value, 2, buf, offset, byte_order); +} + +void encode8(uint8_t value, uint8_t *buf, int *offset, bmkt_byte_order_t byte_order) +{ + encodeN(value, 1, buf, offset, byte_order); +} \ No newline at end of file diff --git a/libfprint/meson.build b/libfprint/meson.build index abd0005..04de603 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -74,6 +74,24 @@ aesx660 = false aes3k = false drivers_sources = [] drivers_cflags = [] +synaptics_drivers_sources = [ + 'drivers/synaptics/src/synaptics.c', + 'drivers/synaptics/src/bmkt.c', + 'drivers/synaptics/src/crc.c', + 'drivers/synaptics/src/util.c', + 'drivers/synaptics/src/enroll.c', + 'drivers/synaptics/src/auth.c', + 'drivers/synaptics/src/bmkt_message.c', + 'drivers/synaptics/src/sensor.c', + 'drivers/synaptics/src/transport/transport.c', + 'drivers/synaptics/src/platform/linux/plat_event.c', + 'drivers/synaptics/src/platform/linux/plat_log.c', + 'drivers/synaptics/src/platform/posix/posix.c', + 'drivers/synaptics/src/transport/usb_transport.c', + 'drivers/synaptics/src/platform/posix/plat_thread.c', + 'drivers/synaptics/src/platform/posix/plat_mutex.c', +] + foreach driver: drivers if driver == 'upekts' drivers_sources += [ 'drivers/upekts.c' ] @@ -146,6 +164,9 @@ foreach driver: drivers if driver == 'elan' drivers_sources += [ 'drivers/elan.c', 'drivers/elan.h' ] endif + if driver == 'synaptics' + drivers_sources += synaptics_drivers_sources + endif endforeach if aeslib @@ -180,6 +201,18 @@ libfprint_sources += configure_file(input: 'empty_file', ]) deps = [ mathlib_dep, glib_dep, libusb_dep, nss_dep, imaging_dep ] + +if driver == 'synaptics' + synaptics_include_directories = [ + 'drivers/synaptics/include', + 'drivers/synaptics/include/platform/linux', + 'drivers/synaptics/include/platform/posix', + 'drivers/synaptics/include/transport' + ] + deps += dependency('threads') + drivers_cflags += ['-DTHREAD_SUPPORT'] +endif + libfprint = library('fprint', libfprint_sources + drivers_sources + nbis_sources + other_sources, soversion: soversion, @@ -188,6 +221,7 @@ libfprint = library('fprint', include_directories: [ root_inc, include_directories('nbis/include'), + include_directories(synaptics_include_directories), ], dependencies: deps, install: true) diff --git a/meson.build b/meson.build index db5008f..4a68264 100644 --- a/meson.build +++ b/meson.build @@ -45,8 +45,8 @@ mathlib_dep = cc.find_library('m', required: false) # Drivers drivers = get_option('drivers').split(',') -all_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan' ] -primitive_drivers = [ 'upekts' ] +all_drivers = [ 'upekts', 'upektc', 'upeksonly', 'vcom5s', 'uru4000', 'aes1610', 'aes1660', 'aes2501', 'aes2550', 'aes2660', 'aes3500', 'aes4000', 'vfs101', 'vfs301', 'vfs5011', 'upektc_img', 'etes603', 'vfs0050', 'elan', 'synaptics' ] +primitive_drivers = [ 'upekts', 'synaptics' ] if drivers == [ 'all' ] drivers = all_drivers