Compare commits

..

31 Commits

Author SHA1 Message Date
Benjamin Berg
88cd932203 fixup! Simplify Synaptics driver
Ignore zreo format length warning from GCC
2019-06-12 14:55:16 +02:00
Benjamin Berg
e85b607965 fixup! Simplify Synaptics driver
Remove invalid cast to (void*) from usb_check_interrupt returns
2019-06-12 14:55:11 +02:00
Benjamin Berg
40a298f43b fixup! Simplify Synaptics driver
missing BMKT_SUCCESS return in usb_check_interrupt
2019-06-12 14:55:06 +02:00
Benjamin Berg
f8eb329a65 fixup! Simplify Synaptics driver
??? Remove set but not used variable

This discards the return value from bmkt_sensor_handle_response, should
there be some sort of error handling there (e.g. printing a warning)?
2019-06-12 14:55:01 +02:00
Benjamin Berg
eb7edc43b8 fixup! Simplify Synaptics driver
Remove unused variables from usb_transport.c
2019-06-12 14:54:55 +02:00
Benjamin Berg
ebff2518ad fixup! Simplify Synaptics driver
remove unused cancel_resp function from synaptics.c
2019-06-12 14:54:50 +02:00
Benjamin Berg
445d46fb6f fixup! Simplify Synaptics driver
Remove unused variables in synaptics.c
2019-06-12 14:54:45 +02:00
Benjamin Berg
477df2a861 fixup! Simplify Synaptics driver
Remove "for (;;)" loop that never looped

It would either return or break at the end, so just remove the loop, it
is not needed.
2019-06-12 14:54:38 +02:00
Benjamin Berg
e4bac112aa fixup! Simplify Synaptics driver
This contains the following changes:
 * Remove the subdirectories for src/include
 * Drop the include directory logic from the build
   (not needed anymore with above, and it was also broken when
   the synaptics driver was not enabled)
2019-06-12 14:54:32 +02:00
Vincent Huang
4c42a090f7 Simplify Synaptics driver 2019-06-12 14:46:23 +02:00
Vincent Huang
65483d51b7 Add function to delete data in sensor.
Add example test app to test delete function.
  Remove sync database function in Synaptics driver.
2019-06-12 14:46:23 +02:00
Vincent Huang
e513848871 Add Synaptics driver 2019-06-12 14:46:23 +02:00
Benjamin Berg
0a45ed7af6 data: Deprecate print storage API
The only API user currently seems to be the examples. fprintd has its
own storage and that will be a good idea in general.

So deprecate the API, we'll need to find a different solution for the
examples eventually.
2019-06-11 18:23:56 +02:00
Benjamin Berg
1db2dc3f58 core: Add guards to public API
Add appropriate g_return_val_if_fail macros to all public API functions
to guard against NULL pointers being passed into libfprint.
2019-06-11 18:23:56 +02:00
Benjamin Berg
953c75575b poll: Remove fpi_timeout_cancel_for_dev
The function was committed by accident as part of commit d18e1053
(lib: Add a way to name timeouts). It is not used anywhere and
fpi_timeout_cancel_all_for_dev exists, is exported and used and serves
the same purpose.
2019-06-11 16:00:19 +02:00
Dave
8c7ff259af elan: Add 04f3:0c42 to the supported devices
Now that all the quirks are in place to support it.
2019-06-06 12:19:31 +02:00
Dave
3e666130c2 elan: Skip more final frames to avoid bulging captures
If users put their finger on the sensor between the bulge and
"un-bulge" area first and then swipe, the captured image would
be bad.

Skipping more frames can reduce the impact, so bump
ELAN_SKIP_LAST_FRAMES to 2.
2019-06-06 12:19:31 +02:00
Dave
2babfa0625 elan: Simplify calibration check for ELAN_0C42
Check for the mean calibration being outside of range to know whether we
require a recalibration. Continue with the usual checks if the
calibration value is within range.
2019-06-06 12:19:31 +02:00
Dave
83af40679a elan: ELAN_0C42 always supports calibration
Split off calibration support checks into elan_supports_calibration()
2019-06-06 12:19:31 +02:00
Dave
ce31c1d704 elan: Work-around one-byte responses being two-bytes long
On the ELAN_0C42 device, one-byte responses are 2 bytes long.
Adapt our expected response length.
2019-06-06 12:19:31 +02:00
Dave
b20a74a22c elan: Work-around sensors returning incorrect dimensions
The dimensions some sensors return is the maximum zero-based index
rather than the number of pixels. Assuming every sensor has an
even number of pixels is safe.
2019-06-06 12:19:31 +02:00
Dave
66461e4c81 elan: Add quirk definition for device 04f3:0c42 2019-06-06 12:19:07 +02:00
Peter Maatman
6ba9439bbb examples: Remove sleep call in enroll examples
The call to sleep(1) inside of the enrollment loop caused a crash
on at least the etes603 driver.

Because in fp_enroll_finger_img the function enters an event
handling loop. This loop needs to start before the next libusb
event timeout. Which would not happen in the etes603 driver
because the timeout there was set to 1 second as well.
2019-05-14 11:38:33 +02:00
Peter Maatman
6764ec79ae etes603: Prevent hang during enroll process
This commit fixes a hang in gnome-settings when trying to enroll a finger.

The same issue could be seen in the enroll example. Previously the enroll
example would hang on "deactivating" because at some point dev->is_active
is set to false and m_exit_start is never called.
2019-05-14 11:37:19 +02:00
Diego
6f4c378933 vfs5011: Add support for Lenovo Preferred Pro Keyboard (KUF1256)
Add support for the Lenovo Preferred Pro USB Fingerprint Keyboard KUF1256
by declaring support for USB ID 138a:0015.

Closes: #125
2019-05-06 09:55:40 +02:00
Bastien Nocera
b121fa2cc9 uru4000: Work-around SELinux AVC warnings when driver starts
Work-around SELinux AVC warnings caused by p11-kit (which is an NSS
dependency) trying to load the root user's p11-kit configs. We disable
this feature using the P11_KIT_NO_USER_CONFIG envvar.

See https://bugzilla.redhat.com/show_bug.cgi?id=1688583
2019-03-21 16:54:06 +01:00
Seong-Joong Kim
ca26e85fd4 uru4000: Fix integer overflow in imaging_run_state()
‘img->key_number’ variable is originally from the device through bulk
endpoint of USB. The variable is immediately assigned to ‘buf[0]’ for
sending to control endpoint of the device. Here, integer overflow may
occur when the ‘img->key_number’ attempts to assign a value that is
outside of type range of ‘char’ to the ‘buf[0]’
2019-02-21 19:06:06 +09:00
Bastien Nocera
0714380360 build: Disable GTK+ demo app by default
Given that it's not usable yet.
2019-01-21 14:38:35 +00:00
Bastien Nocera
b9af7952a4 demo: Fix crash when there are no supported devices
Handle the empty list output from fp_discover_devs() when there are no
supported devices.

Closes: #146
2019-01-21 14:38:35 +00:00
Bastien Nocera
ea6820ed51 lib: Better docs for no devices case in fp_discover_devs()
Document the behaviour of fp_discover_devs() when there are no supported
devices, rather than errors listing the devices.
2019-01-21 14:38:35 +00:00
Bastien Nocera
a1e46de462 lib: Fix examples not working
Remove the sanity check added in commit b1afa9d, having a poll setup
isn't necessary to use timeouts, as long as only sync functions are
used.

Closes: #139
2018-12-30 16:35:33 +01:00
40 changed files with 3845 additions and 51 deletions

View File

@@ -473,8 +473,17 @@ libfprint_demo_window_init (LibfprintDemoWindow *window)
setup_pollfds ();
discovered_devs = fp_discover_devs();
if (!discovered_devs)
if (!discovered_devs) {
libfprint_demo_set_mode (window, ERROR_MODE);
return;
}
/* Empty list? */
if (discovered_devs[0] == NULL) {
fp_dscv_devs_free (discovered_devs);
libfprint_demo_set_mode (window, EMPTY_MODE);
return;
}
if (!fp_driver_supports_imaging(fp_dscv_dev_get_driver(discovered_devs[0]))) {
libfprint_demo_set_mode (window, NOIMAGING_MODE);

View File

@@ -27,6 +27,7 @@ private_headers = [
'vfs301_proto_fragments.h',
'vfs301_proto.h',
'vfs5011_proto.h',
'synaptics.h',
# NBIS
'morph.h',

115
examples/delete.c Normal file
View File

@@ -0,0 +1,115 @@
/*
* Example fingerprint delete finger program, which delete the right index
* finger which has been previously enrolled to disk.
* 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libfprint/fprint.h>
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
{
struct fp_dscv_dev *ddev = discovered_devs[0];
struct fp_driver *drv;
if (!ddev)
return NULL;
drv = fp_dscv_dev_get_driver(ddev);
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
return ddev;
}
int main(void)
{
int r = 1;
struct fp_dscv_dev *ddev;
struct fp_dscv_dev **discovered_devs;
struct fp_dev *dev;
struct fp_print_data *data;
setenv ("G_MESSAGES_DEBUG", "all", 0);
setenv ("LIBUSB_DEBUG", "3", 0);
r = fp_init();
if (r < 0) {
fprintf(stderr, "Failed to initialize libfprint\n");
exit(1);
}
discovered_devs = fp_discover_devs();
if (!discovered_devs) {
fprintf(stderr, "Could not discover devices\n");
goto out;
}
ddev = discover_device(discovered_devs);
if (!ddev) {
fprintf(stderr, "No devices detected.\n");
goto out;
}
dev = fp_dev_open(ddev);
fp_dscv_devs_free(discovered_devs);
if (!dev) {
fprintf(stderr, "Could not open device.\n");
goto out;
}
printf("Opened device. Loading previously enrolled right index finger "
"data...\n");
r = fp_print_data_load(dev, RIGHT_INDEX, &data);
if (r != 0) {
fprintf(stderr, "Failed to load fingerprint, error %d\n", r);
fprintf(stderr, "Did you remember to enroll your right index finger "
"first?\n");
goto out_close;
}
printf("Print loaded. delete data in sensor.\n");
if(!fp_dev_supports_data_in_sensor(dev))
{
printf("This driver doesn't support to store data in sensor.\n");
goto out_close;
}
r = fp_delete_finger(dev, data);
fp_print_data_free(data);
if (r) {
printf("delete finger failed with error %d :(\n", r);
}
else
{
printf("sensor data deleted. now delete host data");
r = fp_print_data_delete(dev, RIGHT_INDEX);
if (r < 0) {
printf("Delete sensor data successfully but delete host data failed. %d :(\n", r);
}
}
out_close:
fp_dev_close(dev);
out:
fp_exit();
return r;
}

View File

@@ -45,8 +45,7 @@ struct fp_print_data *enroll(struct fp_dev *dev) {
do {
struct fp_img *img = NULL;
sleep(1);
printf("\nScan your finger now.\n");
r = fp_enroll_finger_img(dev, &enrolled_print, &img);
@@ -143,7 +142,10 @@ int main(void)
if (!data)
goto out_close;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
r = fp_print_data_save(data, RIGHT_INDEX);
#pragma GCC diagnostic pop
if (r < 0)
fprintf(stderr, "Data save failed, code %d\n", r);

View File

@@ -1,5 +1,5 @@
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture' ]
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture', 'delete' ]
foreach example: examples
executable(example,
example + '.c',

View File

@@ -117,7 +117,10 @@ int main(void)
printf("Opened device. Loading previously enrolled right index finger "
"data...\n");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
r = fp_print_data_load(dev, RIGHT_INDEX, &data);
#pragma GCC diagnostic pop
if (r != 0) {
fprintf(stderr, "Failed to load fingerprint, error %d\n", r);
fprintf(stderr, "Did you remember to enroll your right index finger "

View File

@@ -43,7 +43,6 @@ struct fp_print_data *enroll(struct fp_dev *dev) {
"complete the process.\n", fp_dev_get_nr_enroll_stages(dev));
do {
sleep(1);
printf("\nScan your finger now.\n");
r = fp_enroll_finger(dev, &enrolled_print);
if (r < 0) {

View File

@@ -42,6 +42,7 @@ enum {
VFS5011_ID = 19,
VFS0050_ID = 20,
ELAN_ID = 21,
SYNAPTICS_ID = 22,
};
#endif

View File

@@ -383,6 +383,12 @@ static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev)
return;
}
if (elandev->dev_type == ELAN_0C42) {
/* ELAN_0C42 sends an extra byte in one byte responses */
if (elandev->cmd->response_len == 1)
response_len = 2;
}
if (elandev->cmd->cmd == get_image_cmd.cmd)
/* raw data has 2-byte "pixels" and the frame is vertical */
response_len =
@@ -597,6 +603,14 @@ static int elan_need_calibration(struct elan_dev *elandev)
g_assert(frame_size != 0);
if (elandev->dev_type == ELAN_0C42) {
if (calib_mean > 5500 ||
calib_mean < 2500) {
fp_dbg("Forcing needed recalibration");
return 1;
}
}
for (int i = 0; i < frame_size; i++)
bg_mean += elandev->background[i];
bg_mean /= frame_size;
@@ -621,6 +635,14 @@ enum calibrate_states {
CALIBRATE_NUM_STATES,
};
static gboolean elan_supports_calibration(struct elan_dev *elandev)
{
if (elandev->dev_type == ELAN_0C42)
return TRUE;
return elandev->fw_ver >= ELAN_MIN_CALIBRATION_FW;
}
static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
{
struct fp_img_dev *dev = user_data;
@@ -634,7 +656,7 @@ static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_da
break;
case CALIBRATE_SAVE_BACKGROUND:
elan_save_background(elandev);
if (elandev->fw_ver < ELAN_MIN_CALIBRATION_FW) {
if (!elan_supports_calibration(elandev)) {
fp_dbg("FW does not support calibration");
fpi_ssm_mark_completed(ssm);
} else
@@ -755,6 +777,14 @@ static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_dat
elandev->frame_height = elandev->raw_frame_height =
elandev->last_read[0];
}
/* Work-around sensors returning the sizes as zero-based index
* rather than the number of pixels. */
if ((elandev->frame_width % 2 == 1) &&
(elandev->frame_height % 2 == 1)) {
elandev->frame_width++;
elandev->frame_height++;
elandev->raw_frame_height = elandev->frame_height;
}
if (elandev->frame_height > ELAN_MAX_FRAME_HEIGHT)
elandev->frame_height = ELAN_MAX_FRAME_HEIGHT;
fp_dbg("sensor dimensions, WxH: %dx%d", elandev->frame_width,

View File

@@ -31,6 +31,7 @@
/* devices with quirks */
#define ELAN_0907 (1 << 0)
#define ELAN_0C03 (1 << 1)
#define ELAN_0C42 (1 << 2)
/* devices which don't require frame rotation before assembling */
#define ELAN_NOT_ROTATED ELAN_0C03
@@ -55,7 +56,7 @@
/* number of frames to drop at the end of capture because frames captured
* while the finger is being lifted can be bad */
#define ELAN_SKIP_LAST_FRAMES 1
#define ELAN_SKIP_LAST_FRAMES 2
#define ELAN_CMD_LEN 0x2
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
@@ -207,6 +208,7 @@ static const struct usb_id elan_id_table[] = {
{.vendor = ELAN_VEND_ID,.product = 0x0c31,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c32,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c33,.driver_data = ELAN_ALL_DEV},
{.vendor = ELAN_VEND_ID,.product = 0x0c42,.driver_data = ELAN_0C42},
{0, 0, 0,},
};

View File

@@ -1430,8 +1430,9 @@ static void dev_deactivate(struct fp_img_dev *idev)
/* this can be called even if still activated. */
if (dev->is_active == TRUE) {
dev->is_active = FALSE;
m_exit_start(idev);
}
m_exit_start(idev);
}
static int dev_open(struct fp_img_dev *idev, unsigned long driver_data)

View File

@@ -0,0 +1,260 @@
/*
* 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_dbg_log("%s: context size: %ld", __func__, sizeof(bmkt_ctx_t));
return BMKT_SUCCESS;
}
void bmkt_exit(bmkt_ctx_t *ctx)
{
if (ctx == NULL)
{
return;
}
}
int bmkt_open(bmkt_ctx_t *ctx, bmkt_sensor_t **sensor,
bmkt_general_error_cb_t err_cb, void *err_cb_ctx, libusb_device_handle *usb_handle)
{
int ret;
if (ctx == NULL || sensor == NULL)
{
return BMKT_INVALID_PARAM;
}
*sensor = &ctx->sensor;
memset(*sensor, 0, sizeof(bmkt_sensor_t));
(*sensor)->usb_xport.handle = usb_handle;
ret = bmkt_sensor_open(*sensor, 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_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_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 = BMKT_GENERAL_ERROR;
/* Payload data for enroll_user [1 byte<backup option> 1 byte<finger Id> maximum length: 100 bytes]*/
uint8_t payload[BMKT_MAX_USER_ID_LEN + 2];
uint8_t payload_len = 0;
/* Backup options is not supported for Prometheus. */
uint8_t backup_opt = 0;
if (sensor == NULL || user_id == NULL)
{
return BMKT_INVALID_PARAM;
}
if (user_id_len > BMKT_MAX_USER_ID_LEN)
{
return BMKT_INVALID_PARAM;
}
payload_len = user_id_len + 2;
payload[0] = backup_opt;
payload[1] = finger_id;
memcpy(&payload[2], 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_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;
}
void bmkt_op_set_state(bmkt_sensor_t* sensor, bmkt_op_state_t state)
{
sensor->op_state = state;
}
void bmkt_op_sm(bmkt_sensor_t *sensor)
{
int ret;
int len = 0;
bmkt_dbg_log("bmkt_op_sm state = %d", sensor->op_state);
switch(sensor->op_state)
{
case BMKT_OP_STATE_GET_RESP:
ret = usb_receive_resp_async(&sensor->usb_xport, &len);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("bmkt_op_sm: usb_receive_resp_async failed %d", ret);
}
break;
case BMKT_OP_STATE_WAIT_INTERRUPT:
ret = usb_check_interrupt(&sensor->usb_xport);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("bmkt_op_sm: check_interrupt failed %d", ret);
}
break;
case BMKT_OP_STATE_SEND_ASYNC:
ret = bmkt_sensor_send_async_read_command(sensor);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("bmkt_op_sm: bmkt_sensor_send_async_read_command failed %d", ret);
}
break;
case BMKT_OP_STATE_COMPLETE:
break;
default:
break;
}
}
void bmkt_op_next_state(bmkt_sensor_t* sensor)
{
if(sensor->op_state != BMKT_OP_STATE_COMPLETE)
sensor->op_state = (sensor->op_state + 1) % BMKT_OP_STATE_COMPLETE;
bmkt_op_sm(sensor);
}

View File

@@ -0,0 +1,452 @@
/*
* 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 <stdint.h>
#include "libusb-1.0/libusb.h"
#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
#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
{
int product_id;
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[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,
bmkt_sensor_t ** sensor,
bmkt_general_error_cb_t err_cb,
void * err_cb_ctx,
libusb_device_handle * handle);
/**
* 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 users 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 users fingerprint and stored
* in encrypted storage within the fingerprint sensor module.
* When this command is being executed, fingerprint sensor modules 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_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 users 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 modules 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_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 modules 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_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);
typedef enum
{
BMKT_OP_STATE_START = -1,
BMKT_OP_STATE_GET_RESP,
BMKT_OP_STATE_WAIT_INTERRUPT,
BMKT_OP_STATE_SEND_ASYNC,
BMKT_OP_STATE_COMPLETE,
} bmkt_op_state_t;
void bmkt_op_set_state(bmkt_sensor_t* sensor, bmkt_op_state_t state);
#ifdef __cplusplus
}
#endif
#endif /* _BMKT_H_ */

View File

@@ -0,0 +1,44 @@
/*
* 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 <time.h>
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include "fp_internal.h"
uint32_t extract32(const uint8_t *buf, int *offset);
uint16_t extract16(const uint8_t *buf, int *offset);
uint8_t extract8(const uint8_t *buf, int *offset);
void print_buffer(uint8_t *buf, int len);
#define bmkt_dbg_log fp_dbg
#define bmkt_info_log fp_info
#define bmkt_warn_log fp_warn
#define bmkt_err_log fp_err
void bmkt_op_next_state(bmkt_sensor_t *sensor);
#endif /* _BMKT_INTERNAL_H_ */

View File

@@ -0,0 +1,397 @@
/*
* 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 "usb_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_init_ok(bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
{
bmkt_init_resp_t *init_resp = &resp->response.init_resp;
if (msg_resp->payload_len != 1)
{
return BMKT_UNRECOGNIZED_MESSAGE;
}
init_resp->finger_presence = extract8(msg_resp->payload, NULL);
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);
fps_mode_resp->level2_mode = extract8(msg_resp->payload, &offset);
fps_mode_resp->cmd_id = extract8(msg_resp->payload, &offset);
fps_mode_resp->finger_presence = extract8(msg_resp->payload, &offset);
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);
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);
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);
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);
db_cap_resp->empty = extract8(msg_resp->payload, &offset);
if (msg_resp->payload_len == 4)
{
db_cap_resp->bad_slots = extract8(msg_resp->payload, &offset);
db_cap_resp->corrupt_templates = extract8(msg_resp->payload, &offset);
}
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);
get_enrolled_fingers_resp->fingers[i].template_status = extract8(msg_resp->payload, &offset);
}
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);
get_enroll_templates_resp->query_sequence = extract8(msg_resp->payload, &offset);
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) - 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);
get_enroll_templates_resp->templates[n].finger_id = extract8(msg_resp->payload, &offset);
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);
}
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);
get_version_resp->week = extract8(msg_resp->payload, &offset);
get_version_resp->patch = extract8(msg_resp->payload, &offset);
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:
ret = parse_init_ok(msg_resp, resp);
resp->complete = 1;
break;
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;
}

View File

@@ -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_ */

View File

@@ -0,0 +1,487 @@
/*
* 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 modules 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
* <br>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
* <br>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
* <br>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
* <br>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
* <br>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:
* Users identity has been successfully verified
* <br>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
* <br>Returns list of template records containing user IDs and corresponding finger IDs
* <br>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
* <br>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
* <br> Returns list of IDs of enrolled fingers for a specific user,
* along with template record status corresponding to each enrolled finger
* <br>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.
* <br>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 users 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
* <br>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
* <br>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
* <br>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
* <br>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.
* <br>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
* <br>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
* <br>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
* <br>Failed to retrieve and re-send cached final result
*/
#define BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL 0xE5
/**
* Response payload data structure returned by sensor initialization operation.
*/
typedef struct bmkt_init_resp
{
uint8_t finger_presence; /**< Indicates finger existence on the sensor during startup */
} bmkt_init_resp_t;
/**
* 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_init_resp_t init_resp;
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_ */

View File

@@ -0,0 +1,481 @@
/*
* 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 = usb_get_command_buffer(&sensor->usb_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;
}
cmd[0] = SENSOR_CMD_GET_VERSION;
cmd_len = 1;
ret = usb_send_command_sync(&sensor->usb_xport, cmd_len, &resp, &resp_len);
if (ret != BMKT_SUCCESS)
{
return ret;
}
status = extract16(resp, &offset);
if (status)
{
bmkt_err_log("The sensor reported an error when sending get version command: 0x%x",
status);
return BMKT_SENSOR_MALFUNCTION;
}
if (resp_len < 38)
{
return BMKT_SENSOR_MALFUNCTION;
}
mis_version->build_time = extract32(resp, &offset);
mis_version->build_num = extract32(resp, &offset);
mis_version->version_major = extract8(resp, &offset);
mis_version->version_minor = extract8(resp, &offset);
mis_version->target = extract8(resp, &offset);
mis_version->product = extract8(resp, &offset);
ret = usb_release_command_buffer(&sensor->usb_xport);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("%s: failed to release command buffer: %d", __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, bmkt_general_error_cb_t err_cb, void *err_cb_ctx)
{
int ret;
sensor->seq_num = 1;
sensor->sensor_state = BMKT_SENSOR_STATE_UNINIT;
sensor->usb_xport.sensor = sensor;
ret = usb_open(&sensor->usb_xport);
if (ret != BMKT_SUCCESS)
{
bmkt_err_log("Failed to open transport: %d", 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", ret);
return ret;
}
bmkt_dbg_log("Build Time: %d", sensor->version.build_time);
bmkt_dbg_log("Build Num: %d", sensor->version.build_num);
bmkt_dbg_log("Version: %d.%d", sensor->version.version_major, sensor->version.version_minor);
bmkt_dbg_log("Target: %d", sensor->version.target);
bmkt_dbg_log("Product: %d", sensor->version.product);
return BMKT_SUCCESS;
}
int bmkt_sensor_close(bmkt_sensor_t *sensor)
{
int ret;
sensor->sensor_state = BMKT_SENSOR_STATE_EXIT;
ret = usb_close(&sensor->usb_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;
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", session_ctx->seq_num, sensor->seq_num);
bmkt_op_set_state(sensor, BMKT_OP_STATE_START);
ret = usb_get_command_buffer(&sensor->usb_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", ret);
goto cleanup;
}
ret = usb_send_command(&sensor->usb_xport, msg_len + SENSOR_FW_CMD_HEADER_LEN);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("%s: failed to send ACE command: %d", __func__, ret);
goto cleanup;
}
cleanup:
usb_release_command_buffer(&sensor->usb_xport);
if (ret != BMKT_SUCCESS)
{
release_session_ctx(sensor, session_ctx);
}
return ret;
}
int bmkt_sensor_send_async_read_command(bmkt_sensor_t *sensor)
{
int ret;
uint8_t *cmd;
int cmd_buf_len = 0;
ret = usb_get_command_buffer(&sensor->usb_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 = usb_send_command(&sensor->usb_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", __func__, ret);
}
goto cleanup;
}
cleanup:
usb_release_command_buffer(&sensor->usb_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 = usb_get_command_buffer(&sensor->usb_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", ret);
goto cleanup;
}
ret = usb_send_command_sync(&sensor->usb_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", __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 = usb_release_command_buffer(&sensor->usb_xport);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("%s: failed to release command buffer: %d", __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;
ret = bmkt_parse_message_header(&resp_buf[2], resp_len - 2, msg_resp);
if (ret == BMKT_CORRUPT_MESSAGE)
{
bmkt_warn_log("Corrupt Message Received");
return ret;
}
else if (ret != BMKT_SUCCESS)
{
return ret;
}
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 (msg_resp->seq_num == 0)
{
if (msg_resp->msg_id == BMKT_RSP_GENERAL_ERROR)
{
/* report general error */
bmkt_info_log("General Error!");
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", 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)", 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", 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_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;
}

View File

@@ -0,0 +1,82 @@
/*
* 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 "usb_transport.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_usb_transport_t usb_xport;
bmkt_sensor_version_t version;
bmkt_session_ctx_t pending_sessions[BMKT_MAX_PENDING_SESSIONS];
int empty_session_idx;
int flags;
int seq_num;
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;
bmkt_op_state_t op_state;
} bmkt_sensor_t;
int bmkt_sensor_open(bmkt_sensor_t *sensor,
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_send_async_read_command(bmkt_sensor_t *sensor);
#endif /* _SENSOR_H_ */

View File

@@ -0,0 +1,488 @@
/*
* 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 */
};
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");
bmkt_op_set_state(sdev->sensor, BMKT_OP_STATE_COMPLETE);
fpi_drvcb_report_verify_result(dev, FP_VERIFY_NO_MATCH, NULL);
}
break;
}
return BMKT_SUCCESS;
}
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);
bmkt_op_set_state(sdev->sensor, BMKT_OP_STATE_COMPLETE);
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;
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));
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, general_error_callback, NULL, fpi_dev_get_usb_dev(dev));
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);
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
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);
bmkt_op_set_state(sdev->sensor, BMKT_OP_STATE_COMPLETE);
if(sdev->state == SYNA_STATE_DELETE)
{
/* Return result complete when record doesn't exist, otherwise host data
won't be deleted. */
if(resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
fpi_drvcb_delete_complete(dev, FP_DELETE_COMPLETE);
else
fpi_drvcb_delete_complete(dev, FP_DELETE_FAIL);
}
break;
case BMKT_RSP_DEL_USER_FP_OK:
fp_info("Successfully deleted enrolled user");
bmkt_op_set_state(sdev->sensor, BMKT_OP_STATE_COMPLETE);
if(sdev->state == SYNA_STATE_DELETE)
{
fpi_drvcb_delete_complete(dev, FP_DELETE_COMPLETE);
}
break;
}
return 0;
}
static int enroll_start(struct fp_dev *dev)
{
synaptics_dev *sdev = FP_INSTANCE_DATA(dev);
int result = 0;
char userid[TEMPLATE_ID_SIZE + 1];
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");
synaptics_dev *sdev = FP_INSTANCE_DATA(dev);
sdev->state = SYNA_STATE_IDLE;
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
{
bmkt_op_set_state(sdev->sensor, BMKT_OP_STATE_COMPLETE);
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);
bmkt_op_set_state(sdev->sensor, BMKT_OP_STATE_COMPLETE);
fpi_drvcb_report_verify_result(dev, FP_VERIFY_MATCH, NULL);
break;
}
}
return 0;
}
static int delete_finger(struct fp_dev *dev)
{
synaptics_dev *sdev = FP_INSTANCE_DATA(dev);
int result = 0;
struct fp_print_data *print = fpi_dev_get_delete_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("delete finger !");
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_DELETE;
result = bmkt_delete_enrolled_user(sdev->sensor, 1, print_data->user_id,
user.user_id_len, del_enrolled_user_resp, dev);
if (result != BMKT_SUCCESS)
{
fp_err("Failed to delete enrolled user: %d", result);
goto cleanup;
}
return 0;
cleanup:
return -1;
}
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");
synaptics_dev *sdev = FP_INSTANCE_DATA(dev);
sdev->state = SYNA_STATE_IDLE;
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,
.delete_finger = delete_finger,
};

View File

@@ -0,0 +1,58 @@
/*
* 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 12
#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_DELETE ,
} syna_state_t;
typedef struct synaptics_dev_s
{
bmkt_ctx_t *ctx;
bmkt_sensor_t *sensor;
struct syna_enroll_resp_data enroll_resp_data;
gboolean isFingerOnSensor;
syna_state_t state;
}synaptics_dev;
#endif //__synaptics_h__

View File

@@ -0,0 +1,386 @@
/*
* 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"
#include "drivers_api.h"
#define USB_ASYNC_MESSAGE_PENDING 0x4
static void usb_int_callback(struct libusb_transfer *transfer)
{
bmkt_usb_transport_t *usb_xport = (bmkt_usb_transport_t *)transfer->user_data;
#ifdef TRANSPORT_DEBUG
bmkt_dbg_log("INTERRUPT: (%d) ", transfer->actual_length);
print_buffer(transfer->buffer, transfer->actual_length);
#endif
if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING)
{
libusb_free_transfer(transfer);
bmkt_op_next_state(usb_xport->sensor);
}
else
libusb_submit_transfer(transfer);
}
int usb_check_interrupt(bmkt_usb_transport_t *usb_xport)
{
int ret;
struct libusb_transfer *interrupt_xfer;
interrupt_xfer = libusb_alloc_transfer(0);
if (interrupt_xfer == NULL)
{
return 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_int_callback, usb_xport, 0);
ret = libusb_submit_transfer(interrupt_xfer);
if (ret != LIBUSB_SUCCESS)
{
libusb_free_transfer(interrupt_xfer);
if (ret == LIBUSB_ERROR_NO_DEVICE)
{
return BMKT_SENSOR_MALFUNCTION;
}
else
{
return BMKT_GENERAL_ERROR;
}
}
return BMKT_SUCCESS;
}
int usb_open(bmkt_usb_transport_t *usb_xport)
{
int ret;
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->device = libusb_get_device(usb_xport->handle);
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;
return ret;
}
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;
}
free_config:
libusb_free_config_descriptor(configDesc);
return ret;
}
int usb_close(bmkt_usb_transport_t *usb_xport)
{
if (usb_xport->handle)
{
libusb_release_interface(usb_xport->handle, USB_DEFAULT_INTERFACE);
}
return BMKT_SUCCESS;
}
void usb_in_cb(struct libusb_transfer *transfer)
{
uint8_t *resp_buf;
int resp_len;
bmkt_msg_resp_t msg_resp;
bmkt_usb_transport_t *usb_xport = (bmkt_usb_transport_t *)transfer->user_data;
#ifdef TRANSPORT_DEBUG
bmkt_dbg_log("RX_ASYNC: (%d) ", transfer->actual_length);
print_buffer(transfer->buffer, transfer->actual_length);
#endif
resp_buf = transfer->buffer;
resp_len = transfer->actual_length;
bmkt_sensor_handle_response(usb_xport->sensor, resp_buf, resp_len, &msg_resp);
libusb_free_transfer(transfer);
bmkt_op_next_state(usb_xport->sensor);
}
void usb_out_cb(struct libusb_transfer *transfer)
{
bmkt_usb_transport_t *usb_xport = (bmkt_usb_transport_t *)transfer->user_data;
libusb_free_transfer(transfer);
bmkt_op_next_state(usb_xport->sensor);
}
static int bulk_transfer_async(bmkt_usb_transport_t *usb_xport, uint8_t *buf, int size, uint8_t endpoint,
int *transferred, uint32_t timeout, libusb_transfer_cb_fn callback)
{
int ret;
struct libusb_transfer *transfer;
#ifdef TRANSPORT_DEBUG
if (!(endpoint & 0x80))
{
bmkt_dbg_log("TX2: (%d) ", size);
print_buffer(buf, size);
}
#endif
transfer = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer( transfer, usb_xport->handle, endpoint,
buf, size, callback, usb_xport, 0);
ret = libusb_submit_transfer(transfer);
if (ret != LIBUSB_SUCCESS)
{
libusb_free_transfer(transfer);
if (ret == LIBUSB_ERROR_NO_DEVICE)
{
return BMKT_SENSOR_MALFUNCTION;
}
else
{
return BMKT_GENERAL_ERROR;
}
}
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;
}
int usb_send_command(bmkt_usb_transport_t *usb_xport, int len)
{
int ret;
int tx_len = 0;
ret = bulk_transfer_async(usb_xport, usb_xport->transfer, len, USB_EP_REQUEST, &tx_len, 0, usb_out_cb);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("Failed to send usb command\n");
return ret;
}
return BMKT_SUCCESS;
}
int usb_get_command_buffer(bmkt_usb_transport_t *usb_xport, uint8_t **cmd, int *len)
{
*len = BMKT_MAX_TRANSFER_LEN;
*cmd = usb_xport->transfer;
return BMKT_SUCCESS;
}
int usb_get_response_buffer(bmkt_usb_transport_t *usb_xport, uint8_t **resp, int *len)
{
*len = BMKT_MAX_TRANSFER_LEN;
*resp = usb_xport->transfer;
return BMKT_SUCCESS;
}
int usb_receive_resp_async(bmkt_usb_transport_t *usb_xport, int *len)
{
int ret;
*len = BMKT_MAX_TRANSFER_LEN;
/* Check to make sure the buffer is clear */
memset(usb_xport->transfer, 0, BMKT_MAX_TRANSFER_LEN);
ret = bulk_transfer_async(usb_xport, usb_xport->transfer, *len, USB_EP_REPLY, len, 0, usb_in_cb);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("Failed to send usb command\n");
return ret;
}
return BMKT_SUCCESS;
}
int usb_receive_resp(bmkt_usb_transport_t *usb_xport, int *len)
{
int ret;
*len = BMKT_MAX_TRANSFER_LEN;
/* Check to make sure the buffer is clear */
memset(usb_xport->transfer, 0, BMKT_MAX_TRANSFER_LEN);
ret = bulk_transfer(usb_xport, usb_xport->transfer, *len, USB_EP_REPLY, len, 0);
if (ret != BMKT_SUCCESS)
{
bmkt_dbg_log("Failed to send usb command\n");
return ret;
}
return BMKT_SUCCESS;
}
int usb_send_command_sync(bmkt_usb_transport_t *usb_xport, int len, uint8_t **resp_buf,
int *resp_len)
{
int ret;
int tx_len = 0;
ret = bulk_transfer(usb_xport, usb_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(usb_xport->transfer, 0, BMKT_MAX_TRANSFER_LEN);
ret = bulk_transfer(usb_xport, usb_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 = usb_xport->transfer;
return BMKT_SUCCESS;
}
int usb_reset(bmkt_usb_transport_t *usb_xport)
{
return BMKT_OPERATION_DENIED;
}
int usb_release_command_buffer(bmkt_usb_transport_t *usb_xport)
{
return BMKT_SUCCESS;
}
int usb_release_response_buffer(bmkt_usb_transport_t *usb_xport)
{
return BMKT_SUCCESS;
}

View File

@@ -0,0 +1,76 @@
/*
* 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 "bmkt_internal.h"
#include "libusb-1.0/libusb.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
#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;
uint8_t interrupt_data[USB_INTERRUPT_DATA_SIZE];
bmkt_sensor_t *sensor;
uint8_t transfer[BMKT_MAX_TRANSFER_LEN];
} bmkt_usb_transport_t;
int usb_release_command_buffer(bmkt_usb_transport_t *xport);
int usb_release_response_buffer(bmkt_usb_transport_t *xport);
int usb_open(bmkt_usb_transport_t *xport);
int usb_close(bmkt_usb_transport_t *xport);
int usb_send_command(bmkt_usb_transport_t *xport, int len);
int usb_get_command_buffer(bmkt_usb_transport_t *xport, uint8_t **cmd, int *len);
int usb_get_response_buffer(bmkt_usb_transport_t *xport, uint8_t **resp, int *len);
int usb_receive_resp(bmkt_usb_transport_t *xport, int *len);
int usb_send_command_sync(bmkt_usb_transport_t *xport, int len, uint8_t **resp_buf,
int *resp_len);
int usb_receive_resp_async(bmkt_usb_transport_t *usb_xport, int *len);
int usb_check_interrupt(bmkt_usb_transport_t *usb_xport);
#endif /* _USB_TRANSPORT_H_ */

View File

@@ -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"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-zero-length"
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("");
}
}
bmkt_dbg_log("");
}
#pragma GCC diagnostic pop
uint32_t extract32(const uint8_t *buf, int *offset)
{
uint32_t ret = 0;
int off = 0;
if (offset)
{
off = *offset;
}
ret = GUINT32_FROM_LE(*(uint32_t*)(buf + off));
if (offset)
{
*offset += 4;
}
return ret;
}
uint16_t extract16(const uint8_t *buf, int *offset)
{
uint16_t ret = 0;
int off = 0;
if (offset)
{
off = *offset;
}
ret = GUINT16_FROM_LE(*(uint16_t*)(buf + off));
if (offset)
{
*offset += 2;
}
return ret;
}
uint8_t extract8(const uint8_t *buf, int *offset)
{
uint8_t ret = 0;
int off = 0;
if (offset)
{
off = *offset;
}
ret = *(buf + off);
if (offset)
{
*offset += 1;
}
return ret;
}

View File

@@ -710,7 +710,7 @@ static void imaging_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data
uint32_t key;
uint8_t flags, num_lines;
int i, r, to, dev2;
char buf[5];
unsigned char buf[5];
switch (fpi_ssm_get_cur_state(ssm)) {
case IMAGING_CAPTURE:
@@ -1340,6 +1340,9 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
goto out;
}
/* Disable loading p11-kit's user configuration */
g_setenv ("P11_KIT_NO_USER_CONFIG", "1", TRUE);
/* Initialise NSS early */
rv = NSS_NoDB_Init(".");
if (rv != SECSuccess) {

View File

@@ -879,6 +879,7 @@ static void dev_deactivate(struct fp_img_dev *dev)
static const struct usb_id id_table[] = {
{ .vendor = 0x138a, .product = 0x0010 /* Validity device from some Toshiba laptops */ },
{ .vendor = 0x138a, .product = 0x0011 /* vfs5011 */ },
{ .vendor = 0x138a, .product = 0x0015 /* Validity device from Lenovo Preferred Pro USB Fingerprint Keyboard KUF1256 */ },
{ .vendor = 0x138a, .product = 0x0017 /* Validity device from Lenovo T440 laptops */ },
{ .vendor = 0x138a, .product = 0x0018 /* one more Validity device */ },
{ 0, 0, 0, },

View File

@@ -77,6 +77,9 @@ enum fp_dev_state {
DEV_STATE_CAPTURING,
DEV_STATE_CAPTURE_DONE,
DEV_STATE_CAPTURE_STOPPING,
DEV_STATE_DELETING,
DEV_STATE_DELETE_DONE,
DEV_STATE_DELETE_STOPPING,
};
struct fp_dev {
@@ -96,6 +99,9 @@ struct fp_dev {
/* read-only to drivers */
struct fp_print_data *verify_data;
struct fp_print_data *delete_data;
/* drivers should not mess with any of the below */
enum fp_dev_state state;
int __enroll_stage;
@@ -123,6 +129,8 @@ struct fp_dev {
void *capture_cb_data;
fp_operation_stop_cb capture_stop_cb;
void *capture_stop_cb_data;
fp_delete_cb delete_cb;
void *delete_cb_data;
/* FIXME: better place to put this? */
struct fp_print_data **identify_gallery;

View File

@@ -680,3 +680,58 @@ API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
}
return r;
}
/**
* fp_async_delete_finger:
* @dev: the struct #fp_dev device
* @data: data to delete. Must have been previously enrolled.
* @callback: the callback to call when data deleted.
* @user_data: user data to pass to the callback
*
* Request to delete data in sensor.
*
* Returns: 0 on success, non-zero on error
*/
API_EXPORTED int fp_async_delete_finger(struct fp_dev *dev,
struct fp_print_data *data, fp_delete_cb callback, void *user_data)
{
struct fp_driver *drv;
int r;
g_return_val_if_fail(dev != NULL, -ENODEV);
g_return_val_if_fail (callback != NULL, -EINVAL);
drv = dev->drv;
G_DEBUG_HERE();
if (!drv->delete_finger)
return -ENOTSUP;
dev->state = DEV_STATE_DELETING;
dev->delete_cb = callback;
dev->delete_cb_data = user_data;
dev->delete_data = data;
r = drv->delete_finger(dev);
if (r < 0) {
dev->delete_cb = NULL;
dev->state = DEV_STATE_ERROR;
fp_err("failed to delete data, error %d", r);
}
return r;
}
/* Drivers call this when delete done */
void fpi_drvcb_delete_complete(struct fp_dev *dev, int status)
{
fp_dbg("status %d", status);
BUG_ON(dev->state != DEV_STATE_DELETING);
dev->state = (status) ? DEV_STATE_ERROR : DEV_STATE_DELETE_DONE;
if (dev->delete_cb)
dev->delete_cb(dev, status, dev->delete_cb_data);
}

View File

@@ -36,4 +36,7 @@ void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
struct fp_img *img);
void fpi_drvcb_verify_stopped(struct fp_dev *dev);
void fpi_drvcb_delete_complete(struct fp_dev *dev, int status);
#endif

View File

@@ -270,10 +270,12 @@ static struct fp_dscv_dev *discover_dev(libusb_device *udev)
* fp_discover_devs:
*
* Scans the system and returns a list of discovered devices. This is your
* entry point into finding a fingerprint reader to operate.
* entry point into finding a fingerprint reader to operate. Note that %NULL
* is only returned on error. When there are no supported readers available,
* an empty list is returned instead.
*
* Returns: a nul-terminated list of discovered devices. Must be freed with
* fp_dscv_devs_free() after use.
* Returns: a nul-terminated list of discovered devices or %NULL on error.
* Must be freed with fp_dscv_devs_free() after use.
*/
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
{
@@ -344,6 +346,8 @@ API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
*/
API_EXPORTED struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev)
{
g_return_val_if_fail(dev, NULL);
return dev->drv;
}
@@ -358,6 +362,8 @@ API_EXPORTED struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev)
*/
API_EXPORTED uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev)
{
g_return_val_if_fail(dev, 0);
return fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev));
}
@@ -371,6 +377,8 @@ API_EXPORTED uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev)
*/
API_EXPORTED uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev)
{
g_return_val_if_fail(dev, 0);
return dev->devtype;
}
@@ -400,6 +408,9 @@ enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv)
API_EXPORTED int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev,
struct fp_print_data *print)
{
g_return_val_if_fail(dev, 0);
g_return_val_if_fail(print, 0);
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
fpi_driver_get_data_type(dev->drv), print->driver_id, print->devtype,
print->type);
@@ -420,6 +431,9 @@ API_EXPORTED int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev,
API_EXPORTED int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev,
struct fp_dscv_print *print)
{
g_return_val_if_fail(dev, 0);
g_return_val_if_fail(print, 0);
return fpi_print_data_compatible(dev->drv->id, dev->devtype, 0,
print->driver_id, print->devtype, 0);
}
@@ -443,6 +457,9 @@ API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_print_data(struct fp_dscv_dev *
struct fp_dscv_dev *ddev;
int i;
g_return_val_if_fail(devs, NULL);
g_return_val_if_fail(print, NULL);
for (i = 0; (ddev = devs[i]); i++)
if (fp_dscv_dev_supports_print_data(ddev, print))
return ddev;
@@ -468,6 +485,9 @@ API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev *
struct fp_dscv_dev *ddev;
int i;
g_return_val_if_fail(devs, NULL);
g_return_val_if_fail(print, NULL);
for (i = 0; (ddev = devs[i]); i++) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
@@ -488,6 +508,8 @@ API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev *
*/
API_EXPORTED struct fp_driver *fp_dev_get_driver(struct fp_dev *dev)
{
g_return_val_if_fail(dev, NULL);
return dev->drv;
}
@@ -502,6 +524,8 @@ API_EXPORTED struct fp_driver *fp_dev_get_driver(struct fp_dev *dev)
*/
API_EXPORTED int fp_dev_get_nr_enroll_stages(struct fp_dev *dev)
{
g_return_val_if_fail(dev, 0);
return dev->nr_enroll_stages;
}
@@ -515,6 +539,8 @@ API_EXPORTED int fp_dev_get_nr_enroll_stages(struct fp_dev *dev)
*/
API_EXPORTED uint32_t fp_dev_get_devtype(struct fp_dev *dev)
{
g_return_val_if_fail(dev, 0);
return dev->devtype;
}
@@ -530,6 +556,9 @@ API_EXPORTED uint32_t fp_dev_get_devtype(struct fp_dev *dev)
API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev,
struct fp_print_data *data)
{
g_return_val_if_fail(dev, 0);
g_return_val_if_fail(data, 0);
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype,
data->type);
@@ -550,6 +579,9 @@ API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev,
API_EXPORTED int fp_dev_supports_dscv_print(struct fp_dev *dev,
struct fp_dscv_print *print)
{
g_return_val_if_fail(dev, 0);
g_return_val_if_fail(print, 0);
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
0, print->driver_id, print->devtype, 0);
}
@@ -564,6 +596,8 @@ API_EXPORTED int fp_dev_supports_dscv_print(struct fp_dev *dev,
*/
API_EXPORTED const char *fp_driver_get_name(struct fp_driver *drv)
{
g_return_val_if_fail(drv, NULL);
return drv->name;
}
@@ -577,6 +611,8 @@ API_EXPORTED const char *fp_driver_get_name(struct fp_driver *drv)
*/
API_EXPORTED const char *fp_driver_get_full_name(struct fp_driver *drv)
{
g_return_val_if_fail(drv, NULL);
return drv->full_name;
}
@@ -590,6 +626,8 @@ API_EXPORTED const char *fp_driver_get_full_name(struct fp_driver *drv)
*/
API_EXPORTED uint16_t fp_driver_get_driver_id(struct fp_driver *drv)
{
g_return_val_if_fail(drv, 0);
return drv->id;
}
@@ -603,6 +641,8 @@ API_EXPORTED uint16_t fp_driver_get_driver_id(struct fp_driver *drv)
*/
API_EXPORTED enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv)
{
g_return_val_if_fail(drv, FP_SCAN_TYPE_PRESS);
return drv->scan_type;
}
@@ -621,6 +661,8 @@ API_EXPORTED enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv)
*/
API_EXPORTED int fp_driver_supports_imaging(struct fp_driver *drv)
{
g_return_val_if_fail(drv, 0);
return drv->capture_start != NULL;
}
@@ -639,6 +681,8 @@ API_EXPORTED int fp_driver_supports_imaging(struct fp_driver *drv)
*/
API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev)
{
g_return_val_if_fail(dev, 0);
return dev->drv->capture_start != NULL;
}
@@ -654,9 +698,26 @@ API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev)
*/
API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
{
g_return_val_if_fail(dev, 0);
return dev->drv->identify_start != NULL;
}
/**
* fp_dev_supports_data_in_sensor:
* @dev: the struct #fp_dev device
*
* Determines if a device is capable of storing print data in sensor.
* Not all devices support this functionality.
*
* Returns: 1 if the device is capable of storing data in sensor, 0 otherwise.
*/
API_EXPORTED int fp_dev_supports_data_in_sensor(struct fp_dev *dev)
{
return dev->drv->delete_finger != NULL;
}
/**
* fp_dev_get_img_width:
* @dev: the struct #fp_dev device
@@ -671,6 +732,8 @@ API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
*/
API_EXPORTED int fp_dev_get_img_width(struct fp_dev *dev)
{
g_return_val_if_fail(dev, -1);
if (!dev->img_dev) {
fp_dbg("get image width for non-imaging device");
return -1;
@@ -693,6 +756,8 @@ API_EXPORTED int fp_dev_get_img_width(struct fp_dev *dev)
*/
API_EXPORTED int fp_dev_get_img_height(struct fp_dev *dev)
{
g_return_val_if_fail(dev, -1);
if (!dev->img_dev) {
fp_dbg("get image height for non-imaging device");
return -1;

View File

@@ -87,6 +87,7 @@ struct fp_driver {
int (*identify_stop)(struct fp_dev *dev, gboolean iterating);
int (*capture_start)(struct fp_dev *dev);
int (*capture_stop)(struct fp_dev *dev);
int (*delete_finger)(struct fp_dev *dev);
};
/**

View File

@@ -56,12 +56,15 @@ struct fpi_print_data_item_fp2 {
*
* This page documents the various operations you can do with a stored print.
* Note that by default, "stored prints" are not actually stored anywhere
* except in RAM. For the simple scenarios, libfprint provides a simple API
* for you to save and load the stored prints referring to a single user in
* their home directory. For more advanced users, libfprint provides APIs for
* you to convert print data to a byte string, and to reconstruct stored prints
* except in RAM. Storage needs to be handled by the API user by using the
* fp_print_data_get_data() and fp_print_data_from_data(). This API allows
* to convert print data into byte strings, and to reconstruct stored prints
* from such data at a later point. You are welcome to store these byte strings
* in any fashion that suits you.
*
* The provided API to store data on disk is deprecated and should not be
* used anymore. This API stored the prints in the current user's home
* directory.
*/
/*
@@ -366,6 +369,10 @@ static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger)
* directory beneath the current user's home directory.
*
* Returns: 0 on success, non-zero on error.
*
* Deprecated: Data storage should be handled outside of libfprint.
* See <link linkend="libfprint-Stored-prints.description">stored prints description</link>
* for more information.
*/
API_EXPORTED int fp_print_data_save(struct fp_print_data *data,
enum fp_finger finger)
@@ -478,6 +485,10 @@ static int load_from_file(char *path, struct fp_print_data **data)
* obscure error conditions (e.g. corruption).
*
* Returns: 0 on success, non-zero on error
*
* Deprecated: Data storage should be handled outside of libfprint.
* See <link linkend="libfprint-Stored-prints.description">stored prints description</link>
* for more information.
*/
API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
enum fp_finger finger, struct fp_print_data **data)
@@ -513,6 +524,10 @@ API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
* Removes a stored print from disk previously saved with fp_print_data_save().
*
* Returns: 0 on success, negative on error
*
* Deprecated: Data storage should be handled outside of libfprint.
* See <link linkend="libfprint-Stored-prints.description">stored prints description</link>
* for more information.
*/
API_EXPORTED int fp_print_data_delete(struct fp_dev *dev,
enum fp_finger finger)

View File

@@ -148,3 +148,17 @@ fpi_dev_get_verify_data(struct fp_dev *dev)
{
return dev->verify_data;
}
/**
* fpi_dev_get_delete_data:
* @dev: a struct #fp_dev
*
* Returns the delete data associated with @dev.
* Returns: a struct #fp_print_data pointer or %NULL
*/
struct fp_print_data *
fpi_dev_get_delete_data(struct fp_dev *dev)
{
return dev->delete_data;
}

View File

@@ -43,5 +43,7 @@ libusb_device_handle *fpi_dev_get_usb_dev(struct fp_dev *dev);
void fpi_dev_set_nr_enroll_stages(struct fp_dev *dev,
int nr_enroll_stages);
struct fp_print_data *fpi_dev_get_verify_data(struct fp_dev *dev);
struct fp_print_data *fpi_dev_get_delete_data(struct fp_dev *dev);
#endif

View File

@@ -91,8 +91,6 @@ struct fpi_timeout {
char *name;
};
static gboolean fpi_poll_is_setup(void);
static int timeout_sort_fn(gconstpointer _a, gconstpointer _b)
{
fpi_timeout *a = (fpi_timeout *) _a;
@@ -167,7 +165,6 @@ fpi_timeout *fpi_timeout_add(unsigned int msec,
int r;
g_return_val_if_fail (dev != NULL, NULL);
g_return_val_if_fail (fpi_poll_is_setup(), NULL);
fp_dbg("in %dms", msec);
@@ -210,26 +207,6 @@ void fpi_timeout_cancel(fpi_timeout *timeout)
fpi_timeout_free(timeout);
}
void
fpi_timeout_cancel_for_dev(struct fp_dev *dev)
{
GSList *l;
g_return_if_fail (dev != NULL);
l = active_timers;
while (l) {
struct fpi_timeout *timeout = l->data;
GSList *current = l;
l = l->next;
if (timeout->dev == dev) {
fpi_timeout_free (timeout);
active_timers = g_slist_delete_link (active_timers, current);
}
}
}
/* get the expiry time and optionally the timeout structure for the next
* timeout. returns 0 if there are no expired timers, or 1 if the
* timeval/timeout output parameters were populated. if the returned timeval
@@ -487,12 +464,6 @@ void fpi_poll_exit(void)
libusb_set_pollfd_notifiers(fpi_usb_ctx, NULL, NULL, NULL);
}
static gboolean
fpi_poll_is_setup(void)
{
return (fd_added_cb != NULL && fd_removed_cb != NULL);
}
void
fpi_timeout_cancel_all_for_dev(struct fp_dev *dev)
{

View File

@@ -441,6 +441,72 @@ API_EXPORTED int fp_verify_finger(struct fp_dev *dev,
return fp_verify_finger_img(dev, enrolled_print, NULL);
}
struct sync_delete_data {
gboolean populated;
int result;
};
static void sync_delete_cb(struct fp_dev *dev, int result, void *user_data)
{
struct sync_delete_data *ddata = user_data;
ddata->result = result;
ddata->populated = TRUE;
}
/**
* fp_delete_finger:
* @dev: the struct #fp_dev device to perform the operation.
* @enrolled_data: the id need to delete on sensor. This id is
* returned in previously enrolled with a MIS device.
*
* Perform a delete data operation on sensor. When print data is stored on sensor,
* this function is needed when host deletes enrolled finger.
*
* Returns: negative code on error, otherwise a code from #fp_delete_result
*/
API_EXPORTED int fp_delete_finger(struct fp_dev *dev,
struct fp_print_data *enrolled_data)
{
struct sync_delete_data *ddata;
gboolean stopped = FALSE;
int r;
if (!enrolled_data) {
fp_err("no print given");
return -EINVAL;
}
if (!fp_dev_supports_print_data(dev, enrolled_data)) {
fp_err("print is not compatible with device");
return -EINVAL;
}
fp_dbg("to be handled by %s", dev->drv->name);
ddata = g_malloc0(sizeof(struct sync_delete_data));
r = fp_async_delete_finger(dev, enrolled_data, sync_delete_cb, ddata);
if (r < 0) {
fp_dbg("delete_finger error %d", r);
g_free(ddata);
return r;
}
while (!ddata->populated) {
r = fp_handle_events();
if (r < 0)
goto out;
}
r = ddata->result;
fp_dbg("delete_finger result %d", r);
out:
g_free(ddata);
return r;
}
struct sync_identify_data {
gboolean populated;
int result;

View File

@@ -267,19 +267,26 @@ int fp_verify_finger(struct fp_dev *dev,
struct fp_print_data *enrolled_print);
int fp_dev_supports_identification(struct fp_dev *dev);
int fp_dev_supports_data_in_sensor(struct fp_dev *dev);
int fp_identify_finger_img(struct fp_dev *dev,
struct fp_print_data **print_gallery, size_t *match_offset,
struct fp_img **img);
int fp_identify_finger(struct fp_dev *dev,
struct fp_print_data **print_gallery, size_t *match_offset);
int fp_delete_finger(struct fp_dev *dev,
struct fp_print_data *enrolled_print);
/* Data handling */
int fp_print_data_load(struct fp_dev *dev, enum fp_finger finger,
struct fp_print_data **data);
struct fp_print_data **data) LIBFPRINT_DEPRECATED;
int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
struct fp_print_data **data) LIBFPRINT_DEPRECATED;
int fp_print_data_save(struct fp_print_data *data, enum fp_finger finger);
int fp_print_data_delete(struct fp_dev *dev, enum fp_finger finger);
int fp_print_data_save(struct fp_print_data *data, enum fp_finger finger)
LIBFPRINT_DEPRECATED;
int fp_print_data_delete(struct fp_dev *dev, enum fp_finger finger)
LIBFPRINT_DEPRECATED;
void fp_print_data_free(struct fp_print_data *data);
size_t fp_print_data_get_data(struct fp_print_data *data, unsigned char **ret);
struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
@@ -449,6 +456,22 @@ int fp_async_capture_start(struct fp_dev *dev, int unconditional, fp_img_operati
int fp_async_capture_stop(struct fp_dev *dev, fp_operation_stop_cb callback, void *user_data);
/**
* fp_delete_result:
* @FP_DELETE_COMPLETE: Delete completed successfully.
* @FP_DELETE_FAIL: Delete failed
*
*/
enum fp_delete_result {
FP_DELETE_COMPLETE = 0,
FP_DELETE_FAIL = 1,
};
typedef void (*fp_delete_cb)(struct fp_dev *dev, int status, void *user_data);
int fp_async_delete_finger(struct fp_dev *dev, struct fp_print_data *data, fp_delete_cb callback, void *user_data);
#ifdef __cplusplus
}
#endif

View File

@@ -74,6 +74,7 @@ aesx660 = false
aes3k = false
drivers_sources = []
drivers_cflags = []
foreach driver: drivers
if driver == 'upekts'
drivers_sources += [ 'drivers/upekts.c' ]
@@ -146,6 +147,16 @@ foreach driver: drivers
if driver == 'elan'
drivers_sources += [ 'drivers/elan.c', 'drivers/elan.h' ]
endif
if driver == 'synaptics'
drivers_sources += [
'drivers/synaptics/synaptics.c',
'drivers/synaptics/bmkt.c',
'drivers/synaptics/util.c',
'drivers/synaptics/bmkt_message.c',
'drivers/synaptics/sensor.c',
'drivers/synaptics/usb_transport.c',
]
endif
endforeach
if aeslib
@@ -180,6 +191,7 @@ libfprint_sources += configure_file(input: 'empty_file',
])
deps = [ mathlib_dep, glib_dep, libusb_dep, nss_dep, imaging_dep ]
libfprint = library('fprint',
libfprint_sources + drivers_sources + nbis_sources + other_sources,
soversion: soversion,

View File

@@ -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

View File

@@ -17,7 +17,7 @@ option('x11-examples',
option('gtk-examples',
description: 'Whether to build GTK+ example applications',
type: 'boolean',
value: true)
value: false)
option('doc',
description: 'Whether to build the API documentation',
type: 'boolean',