Compare commits

..

12 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
65 changed files with 3755 additions and 1510 deletions

View File

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

View File

@@ -1,3 +0,0 @@
These are example images from NIST and are not copyrighted.
The PNG files have been generated by using the greyscale data as a mask.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

View File

@@ -1,86 +0,0 @@
#!/usr/bin/env python3
# This script can be used together with the virtual_imgdev to simulate an
# image based fingerprint reader.
#
# To use, set the FP_VIRTUAL_IMGDEV environment variable for both the
# libfprint using program (e.g. fprintd) and this script.
#
# Usually this would work by adding it into the systemd unit file. The
# best way of doing so is to create
# /etc/systemd/system/fprintd.service.d/fprintd-test.conf
#
# [Service]
# RuntimeDirectory=fprint
# Environment=FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock
# Environment=G_MESSAGES_DEBUG=all
# ReadWritePaths=$RUNTIME_DIR
#
# After that run:
#
# systemctl daemon-reload
# systemctl restart fprintd.service
#
# You may also need to disable selinux.
#
# Then run this script with e.g.
# FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock ./sendvirtimg.py prints/whorl.png
import cairo
import sys
import os
import socket
import struct
if len(sys.argv) == 2:
png = cairo.ImageSurface.create_from_png(sys.argv[1])
# Cairo wants 4 byte aligned rows, so just add a few pixel if necessary
w = png.get_width()
h = png.get_height()
w = (w + 3) // 4 * 4
h = (h + 3) // 4 * 4
img = cairo.ImageSurface(cairo.Format.A8, w, h)
cr = cairo.Context(img)
cr.set_source_rgba(1, 1, 1, 1)
cr.paint()
cr.set_source_rgba(0, 0, 0, 0)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.set_source_surface(png)
cr.paint()
else:
sys.stderr.write('You need to pass a PNG with an alpha channel!\n')
sys.exit(1)
def write_dbg_img():
dbg_img_rgb = cairo.ImageSurface(cairo.Format.RGB24, img.get_width(), img.get_height())
dbg_cr = cairo.Context(dbg_img_rgb)
dbg_cr.set_source_rgb(0, 0, 0)
dbg_cr.paint()
dbg_cr.set_source_rgb(1, 1, 1)
dbg_cr.mask_surface(img, 0, 0)
dbg_img_rgb.write_to_png('/tmp/test.png')
#write_dbg_img()
# Send image through socket
sockaddr = os.environ['FP_VIRTUAL_IMGDEV']
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(sockaddr)
mem = img.get_data()
mem = mem.tobytes()
assert len(mem) == img.get_width() * img.get_height()
encoded_img = struct.pack('ii', img.get_width(), img.get_height())
encoded_img += mem
sock.sendall(encoded_img)

View File

@@ -1,148 +0,0 @@
#!/usr/bin/env python3
# This script can be used together with the virtual_misdev to simulate an
# match-in-sensor device with internal storage.
#
# To use, set the FP_VIRTUAL_MISDEV environment variable for both the
# libfprint using program (e.g. fprintd) and this script.
#
# Usually this would work by adding it into the systemd unit file. The
# best way of doing so is to create
# /etc/systemd/system/fprintd.service.d/fprintd-test.conf
#
# [Service]
# RuntimeDirectory=fprint
# Environment=FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock
# Environment=G_MESSAGES_DEBUG=all
# ReadWritePaths=$RUNTIME_DIR
#
# After that run:
#
# systemctl daemon-reload
# systemctl restart fprintd.service
#
# You may also need to disable selinux.
#
# Then run this script with e.g.
# FP_VIRTUAL_IMGDEV=/run/fprint/virtimg_sock ./virtmissensor.py /tmp/storage
#
# Please note that the storage file should be pre-created with a few lines
# Each line represents a slot, if a print is stored, then it will contain a
# UUID (defined by the driver) and a matching string to identify it again.
# Note that the last slot line should not end with a \n
import sys
import os
import socket
import struct
import argparse
parser = argparse.ArgumentParser(description='Play virtual fingerprint device with internal storage.')
parser.add_argument('storage', metavar='storage', type=argparse.FileType('r+'),
help='The "storage" database (one line per slot)')
parser.add_argument('-e', dest='enroll', type=str,
help='Enroll a print using the string as identifier')
parser.add_argument('-v', dest='verify', type=str,
help='Verify print if the stored identifier matches the given identifier')
parser.add_argument('-d', dest='delete', action='store_const', const=True,
help='Delete print as requested by driver')
args = parser.parse_args()
cnt = 0
if args.enroll:
cnt += 1
if args.verify:
cnt += 1
if args.delete:
cnt += 1
assert cnt == 1, 'You need to give exactly one command argument, -e or -v'
prints = []
for slot in args.storage.read().split('\n'):
split = slot.split(' ', 1)
if len(split) == 2:
prints.append(split)
else:
prints.append(None)
# Send image through socket
sockaddr = os.environ['FP_VIRTUAL_MISDEV']
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(sockaddr)
# Assume we get a full message
msg = sock.recv(1024)
assert(msg[-1] == ord(b'\n'))
if args.enroll:
if not msg.startswith(b'ENROLL '):
sys.stderr.write('Expected to enroll, but driver is not ready for enrolling (%s)\n' % str(msg.split(b' ', 1)[0]))
sys.exit(1)
uuid = msg[7:-1].decode('utf-8')
for slot in prints:
if slot is not None and slot[0] == uuid:
sock.sendall(b'2\n') # ENROLL_FAIL
sys.stderr.write('Failed to enroll; UUID has already been stored!\n')
sys.exit(1)
# Find an empty slot
for i, slot in enumerate(prints):
if slot is not None:
continue
prints[i] = (uuid, args.enroll)
sock.sendall(b'1\n') # ENROLL_COMPLETE
break
else:
# TODO: 2: ENROLL_FAIL, but we should send no empty slot!
sock.sendall(b'2\n') # ENROLL_FAIL
sys.stderr.write('Failed to enroll, no free slots!\n')
sys.exit(1)
elif args.verify:
if not msg.startswith(b'VERIFY '):
sys.stderr.write('Expected to verify, but driver is not ready for verifying (%s)\n' % str(msg.split(b' ', 1)[0]))
sys.exit(1)
uuid = msg[7:-1].decode('utf-8')
for slot in prints:
if slot is not None and slot[0] == uuid:
if slot[1] == args.verify:
sock.sendall(b'1\n') # VERIFY_MATCH
else:
sock.sendall(b'0\n') # VERIFY_NO_MATCH
sys.exit(0)
else:
sys.stderr.write('Slot ID is unknown, returning error\n')
sock.sendall(b'-1') # error, need way to report that print is unkown
elif args.delete:
if not msg.startswith(b'DELETE '):
sys.stderr.write('Expected to delete, but driver is not ready for deleting (%s)\n' % str(msg.split(b' ', 1)[0]))
sys.exit(1)
uuid = msg[7:-1].decode('utf-8')
for i, slot in enumerate(prints):
if slot is not None and slot[0] == uuid:
if slot[0] == uuid:
prints[i] = None
sock.sendall(b'0\n') # DELETE_COMPLETE
break
else:
sys.stderr.write('Slot ID is unknown, just report back complete\n')
sock.sendall(b'0') # DELETE_COMPLETE
prints_str = '\n'.join('' if p is None else '%s %s' % (p[0], p[1]) for p in prints)
prints_human_str = '\n'.join('empty slot' if p is None else '%s %s' % (p[0], p[1]) for p in prints)
print('Prints stored now:')
print(prints_human_str)
args.storage.seek(0)
args.storage.truncate()
args.storage.write(prints_str)

View File

@@ -820,8 +820,7 @@ struct fp_img_driver aes1610_driver = {
.id = AES1610_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES1610",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,

View File

@@ -97,8 +97,7 @@ struct fp_img_driver aes1660_driver = {
.id = AES1660_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES1660",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,

View File

@@ -862,8 +862,7 @@ struct fp_img_driver aes2501_driver = {
.id = AES2501_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES2501",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,

View File

@@ -606,8 +606,7 @@ struct fp_img_driver aes2550_driver = {
.id = AES2550_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES2550/AES2810",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,

View File

@@ -100,8 +100,7 @@ struct fp_img_driver aes2660_driver = {
.id = AES2660_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES2660",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,

View File

@@ -165,8 +165,7 @@ struct fp_img_driver aes3500_driver = {
.id = AES3500_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES3500",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,

View File

@@ -162,8 +162,7 @@ struct fp_img_driver aes4000_driver = {
.id = AES4000_ID,
.name = FP_COMPONENT,
.full_name = "AuthenTec AES4000",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,

View File

@@ -82,7 +82,7 @@ static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
data[data_offset++] = regwrite->value;
}
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev (FP_DEV(wdata->imgdev)), EP_OUT, data,
libusb_fill_bulk_transfer(transfer, FP_DEV(wdata->imgdev)->udev, EP_OUT, data,
alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
r = libusb_submit_transfer(transfer);
if (r < 0) {

View File

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

View File

@@ -973,8 +973,7 @@ struct fp_img_driver elan_driver = {
.id = ELAN_ID,
.name = FP_COMPONENT,
.full_name = "ElanTech Fingerprint Sensor",
.bus = BUS_TYPE_USB,
.id_table.usb = elan_id_table,
.id_table = elan_id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,

View File

@@ -1481,8 +1481,7 @@ struct fp_img_driver etes603_driver = {
.id = ETES603_ID,
.name = FP_COMPONENT,
.full_name = "EgisTec ES603",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},
.flags = 0,

View File

@@ -305,8 +305,7 @@ struct fp_img_driver fdu2000_driver = {
.id = FDU2000_ID,
.name = FP_COMPONENT,
.full_name = "Secugen FDU 2000",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.img_height = RAW_IMAGE_HEIGTH,

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

@@ -1348,10 +1348,9 @@ struct fp_img_driver upeksonly_driver = {
.id = UPEKSONLY_ID,
.name = FP_COMPONENT,
.full_name = "UPEK TouchStrip Sensor-Only",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
.usb_discover = dev_discover,
.discover = dev_discover,
},
.flags = 0,
.img_width = -1,

View File

@@ -463,8 +463,7 @@ struct fp_img_driver upektc_driver = {
.id = UPEKTC_ID,
.name = FP_COMPONENT,
.full_name = "UPEK TouchChip/Eikon Touch 300",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,

View File

@@ -631,10 +631,9 @@ struct fp_img_driver upektc_img_driver = {
.id = UPEKTC_IMG_ID,
.name = FP_COMPONENT,
.full_name = "Upek TouchChip Fingerprint Coprocessor",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
.usb_discover = discover,
.discover = discover,
},
.flags = 0,
.img_height = IMAGE_HEIGHT,

View File

@@ -1424,8 +1424,7 @@ struct fp_driver upekts_driver = {
.id = UPEKTS_ID,
.name = FP_COMPONENT,
.full_name = "UPEK TouchStrip",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
.open = dev_init,
.close = dev_exit,

View File

@@ -1431,8 +1431,7 @@ struct fp_img_driver uru4000_driver = {
.id = URU4000_ID,
.name = FP_COMPONENT,
.full_name = "Digital Persona U.are.U 4000/4000B/4500",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE,

View File

@@ -360,8 +360,7 @@ struct fp_img_driver vcom5s_driver = {
.id = VCOM5S_ID,
.name = FP_COMPONENT,
.full_name = "Veridicom 5thSense",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,

View File

@@ -773,8 +773,7 @@ struct fp_img_driver vfs0050_driver = {
.id = VFS0050_ID,
.name = FP_COMPONENT,
.full_name = "Validity VFS0050",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},

View File

@@ -1529,8 +1529,7 @@ struct fp_img_driver vfs101_driver =
.id = VFS101_ID,
.name = FP_COMPONENT,
.full_name = "Validity VFS101",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},

View File

@@ -271,8 +271,7 @@ struct fp_img_driver vfs301_driver =
.id = VFS301_ID,
.name = FP_COMPONENT,
.full_name = "Validity VFS301",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},

View File

@@ -890,8 +890,7 @@ struct fp_img_driver vfs5011_driver = {
.id = VFS5011_ID,
.name = "vfs5011",
.full_name = "Validity VFS5011",
.bus = BUS_TYPE_USB,
.id_table.usb = id_table,
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
},

View File

@@ -1,225 +0,0 @@
/*
* Virtual driver for image device debugging
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* 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
*/
/*
* This is a virtual driver to debug the image based drivers. A small
* python script is provided to connect to it via a socket, allowing
* prints to be sent to this device programatically.
* Using this it is possible to test libfprint and fprintd.
*/
#define FP_COMPONENT "virtual_imgdev"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <stdio.h>
#include "drivers_api.h"
struct virt_dev {
fpi_io_condition *socket_io_cond;
fpi_io_condition *client_io_cond;
gint socket_fd;
gint client_fd;
struct fp_img *recv_img;
gssize recv_img_data_bytes;
gssize recv_img_hdr_bytes;
gint recv_img_hdr[2];
};
static void
client_socket_cb (struct fp_dev *dev, int fd, short int events, void *data)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
gboolean nodata = FALSE;
gssize len;
if (!virt->recv_img) {
/* Reading the header, i.e. width/height. */
len = read(fd,
(guint8*)virt->recv_img_hdr + virt->recv_img_hdr_bytes,
sizeof(virt->recv_img_hdr) - virt->recv_img_hdr_bytes);
fp_dbg("Received %zi bytes from client!", len);
if (len > 0) {
virt->recv_img_hdr_bytes += len;
/* Got the full header, create an image for further processing. */
if (virt->recv_img_hdr_bytes == sizeof(virt->recv_img_hdr)) {
virt->recv_img_data_bytes = 0;
virt->recv_img = fpi_img_new (virt->recv_img_hdr[0] * virt->recv_img_hdr[1]);
virt->recv_img->width = virt->recv_img_hdr[0];
virt->recv_img->height = virt->recv_img_hdr[1];
virt->recv_img->flags = 0;
}
}
} else {
len = read(fd,
(guint8*)virt->recv_img->data + virt->recv_img_data_bytes,
virt->recv_img->length - virt->recv_img_data_bytes);
fp_dbg("Received %zi bytes from client!", len);
if (len > 0) {
virt->recv_img_data_bytes += len;
if (virt->recv_img_data_bytes == virt->recv_img->length) {
/* Submit received image to frontend */
fpi_imgdev_report_finger_status (FP_IMG_DEV (dev), TRUE);
fpi_imgdev_image_captured(FP_IMG_DEV (dev), virt->recv_img);
virt->recv_img = NULL;
fpi_imgdev_report_finger_status (FP_IMG_DEV (dev), FALSE);
}
}
}
if (len <= 0) {
fp_dbg("Client disconnected!");
close (virt->client_fd);
virt->client_fd = -1;
virt->recv_img_hdr_bytes = 0;
if (virt->recv_img)
fp_img_free (virt->recv_img);
virt->recv_img = NULL;
fpi_io_condition_remove (virt->client_io_cond);
virt->client_io_cond = NULL;
}
}
static void
new_connection_cb (struct fp_dev *dev, int fd, short int events, void *data)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
int new_client_fd;
new_client_fd = accept4(fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
fp_dbg("Got a new connection!");
/* Already have a connection, reject this one */
if (virt->client_fd >= 0) {
fp_warn("Rejecting new connection as we already have one!");
close (new_client_fd);
return;
}
virt->client_fd = new_client_fd;
virt->client_io_cond = fpi_io_condition_add (virt->client_fd, POLL_IN, client_socket_cb, dev, NULL);
}
static int
dev_init(struct fp_img_dev *dev, unsigned long driver_data)
{
struct virt_dev *virt;
const char *env;
struct sockaddr_un addr = {
.sun_family = AF_UNIX
};
G_DEBUG_HERE();
virt = g_new0(struct virt_dev, 1);
fp_dev_set_instance_data(FP_DEV(dev), virt);
virt->client_fd = -1;
env = fpi_dev_get_virtual_env (FP_DEV (dev));
virt->socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (virt->socket_fd < 0) {
fp_err("Could not create socket: %m");
return virt->socket_fd;
}
strncpy (addr.sun_path, env, sizeof(addr.sun_path) - 1);
unlink(env);
if (bind(virt->socket_fd, &addr, sizeof(struct sockaddr_un)) < 0) {
fp_err("Could not bind address '%s': %m", addr.sun_path);
close (virt->socket_fd);
virt->socket_fd = -1;
return -1;
}
if (listen (virt->socket_fd, 1) < 0) {
fp_err("Could not open socket for listening: %m");
close (virt->socket_fd);
virt->socket_fd = -1;
return -1;
}
virt->socket_io_cond = fpi_io_condition_add (virt->socket_fd, POLL_IN, new_connection_cb, FP_DEV (dev), NULL);
fpi_imgdev_open_complete(dev, 0);
return 0;
}
static void dev_deinit(struct fp_img_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(FP_DEV(dev));
G_DEBUG_HERE();
if (virt->client_fd >= 0) {
fpi_io_condition_remove (virt->client_io_cond);
close (virt->client_fd);
}
if (virt->socket_fd >= 0) {
fpi_io_condition_remove (virt->socket_io_cond);
close (virt->socket_fd);
}
g_free(virt);
fpi_imgdev_close_complete(dev);
}
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
{
G_DEBUG_HERE();
fpi_imgdev_activate_complete (dev, 0);
return 0;
}
static void dev_deactivate(struct fp_img_dev *dev)
{
G_DEBUG_HERE();
fpi_imgdev_deactivate_complete (dev);
}
struct fp_img_driver virtual_imgdev_driver = {
.driver = {
.id = VIRTUAL_IMG_ID,
.name = FP_COMPONENT,
.full_name = "Virtual image device for debugging",
.bus = BUS_TYPE_VIRTUAL,
.id_table.virtual_envvar = "FP_VIRTUAL_IMGDEV",
.scan_type = FP_SCAN_TYPE_PRESS,
},
.flags = 0,
.open = dev_init,
.close = dev_deinit,
.activate = dev_activate,
.deactivate = dev_deactivate,
};

View File

@@ -1,424 +0,0 @@
/*
* Virtual match-in-sensor device with internal storage
*
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
*
* 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
*/
/*
* This is a virtual driver to debug features that are relevant for
* match-in-sensor (MIS) devices that store data on the sensor itself.
* In this case data needs to be deleted both locally and from the device
* and we should support garbage collection.
*
* The protocol is line based, when a verify/enroll/etc. command is started
* (or is active when connecting) then we send the command and the UUID
* terminated by a newline.
*
* IDLE\n
* VERIFY UUID\n
* ENROLL UUID\n
* DELETE UUID\n (planned)
* LIST (planned)
*
* The other end simply responds with an integer (terminated by newline)
* that matches the internal fprint return codes.
*/
#define FP_COMPONENT "virtual_misdev"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include <stdio.h>
#include "drivers_api.h"
#include "fpi-async.h"
#define VIRT_ENROLL_STAGES 1
enum virtdev_state {
STATE_IDLE = 0,
STATE_VERIFY,
STATE_ENROLL,
STATE_DELETE,
};
struct virt_dev {
enum virtdev_state state;
gchar *curr_uuid;
fpi_io_condition *socket_io_cond;
fpi_io_condition *client_io_cond;
gint socket_fd;
gint client_fd;
gssize recv_len;
guchar *recv_buf;
};
static void send_status(struct fp_dev *dev);
static void
handle_response (struct fp_dev *dev, guchar *buf, gssize len)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
gint result = atoi ((gchar*) buf);
switch (virt->state) {
case STATE_IDLE:
fp_info ("Received unexpected status code %i\n", virt->state);
break;
case STATE_VERIFY:
fp_info ("Reporting verify results back %i\n", result);
fpi_drvcb_report_verify_result (dev, result, NULL);
break;
case STATE_ENROLL: {
struct fp_print_data * fdata = NULL;
fp_info ("Reporting enroll results back %i\n", result);
/* If the enroll is "done", then report back the UUID for the print. */
if (result == FP_ENROLL_COMPLETE) {
struct fp_print_data_item *item = NULL;
fdata = fpi_print_data_new (dev);
item = fpi_print_data_item_new(strlen(virt->curr_uuid));
memcpy(item->data, virt->curr_uuid, strlen(virt->curr_uuid));
fpi_print_data_add_item(fdata, item);
}
fpi_drvcb_enroll_stage_completed (dev, result, fdata, NULL);
break;
}
case STATE_DELETE:
fp_info ("Reporting delete results back %i\n", result);
virt->state = STATE_IDLE;
g_free (virt->curr_uuid);
virt->curr_uuid = NULL;
fpi_drvcb_delete_complete (dev, result);
send_status(dev);
break;
default:
g_assert_not_reached();
}
}
static void
send_status(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
gchar *msg = NULL;
if (virt->client_fd < 0)
return;
switch (virt->state) {
case STATE_IDLE:
msg = g_strdup ("IDLE\n");
break;
case STATE_ENROLL:
msg = g_strdup_printf ("ENROLL %s\n", virt->curr_uuid);
break;
case STATE_VERIFY:
msg = g_strdup_printf ("VERIFY %s\n", virt->curr_uuid);
break;
case STATE_DELETE:
msg = g_strdup_printf ("DELETE %s\n", virt->curr_uuid);
break;
}
send(virt->client_fd, msg, strlen(msg), MSG_NOSIGNAL);
g_free (msg);
}
static void
client_socket_cb (struct fp_dev *dev, int fd, short int events, void *data)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
guchar *pos;
guchar buf[512];
gssize len;
len = read(fd, buf, sizeof(buf));
fp_dbg("Received %zi bytes from client!", len);
if (len > 0) {
virt->recv_buf = g_realloc(virt->recv_buf, virt->recv_len + len);
memcpy(virt->recv_buf + virt->recv_len, buf, len);
virt->recv_len += len;
while ((pos = memmem(virt->recv_buf, virt->recv_len, "\n", 1))) {
/* Found a newline, parse the command */
fp_dbg("got a command response! %p %p", virt->recv_buf, pos);
*pos = '\0';
handle_response(dev, virt->recv_buf, pos - virt->recv_buf);
/* And remove the parsed part from the buffer */
virt->recv_len = virt->recv_len - (pos - virt->recv_buf) - 1;
memmove(pos, virt->recv_buf, virt->recv_len);
virt->recv_buf = realloc(virt->recv_buf, virt->recv_len);
}
} else {
fp_dbg("Client disconnected!");
close (virt->client_fd);
virt->client_fd = -1;
fpi_io_condition_remove (virt->client_io_cond);
virt->client_io_cond = NULL;
g_free(virt->recv_buf);
virt->recv_buf = NULL;
virt->recv_len = 0;
}
}
static void
new_connection_cb (struct fp_dev *dev, int fd, short int events, void *data)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
int new_client_fd;
new_client_fd = accept4(fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
fp_dbg("Got a new connection!");
/* Already have a connection, reject this one */
if (virt->client_fd >= 0) {
fp_warn("Rejecting new connection as we already have one!");
close (new_client_fd);
return;
}
virt->client_fd = new_client_fd;
virt->client_io_cond = fpi_io_condition_add (virt->client_fd, POLL_IN, client_socket_cb, dev, NULL);
send_status(dev);
}
static int
dev_init(struct fp_dev *dev, unsigned long driver_data)
{
struct virt_dev *virt;
const char *env;
struct sockaddr_un addr = {
.sun_family = AF_UNIX
};
G_DEBUG_HERE();
fpi_dev_set_nr_enroll_stages(dev, VIRT_ENROLL_STAGES);
virt = g_new0(struct virt_dev, 1);
fp_dev_set_instance_data(dev, virt);
virt->client_fd = -1;
env = fpi_dev_get_virtual_env (dev);
virt->socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (virt->socket_fd < 0) {
fp_err("Could not create socket: %m");
return virt->socket_fd;
}
strncpy (addr.sun_path, env, sizeof(addr.sun_path) - 1);
unlink(env);
if (bind(virt->socket_fd, &addr, sizeof(struct sockaddr_un)) < 0) {
fp_err("Could not bind address '%s': %m", addr.sun_path);
close (virt->socket_fd);
virt->socket_fd = -1;
return -1;
}
if (listen (virt->socket_fd, 1) < 0) {
fp_err("Could not open socket for listening: %m");
close (virt->socket_fd);
virt->socket_fd = -1;
return -1;
}
virt->socket_io_cond = fpi_io_condition_add (virt->socket_fd, POLL_IN, new_connection_cb, dev, NULL);
fpi_drvcb_open_complete(dev, 0);
return 0;
}
static void dev_deinit(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
G_DEBUG_HERE();
if (virt->client_fd >= 0) {
fpi_io_condition_remove (virt->client_io_cond);
close (virt->client_fd);
}
if (virt->socket_fd >= 0) {
fpi_io_condition_remove (virt->socket_io_cond);
close (virt->socket_fd);
}
g_free (virt->curr_uuid);
virt->curr_uuid = NULL;
g_free(virt);
fpi_drvcb_close_complete(dev);
}
static int enroll_start(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
G_DEBUG_HERE();
if (virt->state != STATE_IDLE)
return -1;
g_assert (virt->curr_uuid == NULL);
virt->state = STATE_ENROLL;
virt->curr_uuid = g_uuid_string_random ();
send_status(dev);
fpi_drvcb_enroll_started(dev, 0);
return 0;
}
static int enroll_stop(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
G_DEBUG_HERE();
if (virt->state != STATE_ENROLL)
return -1;
virt->state = STATE_IDLE;
g_free (virt->curr_uuid);
virt->curr_uuid = NULL;
send_status(dev);
fpi_drvcb_enroll_stopped(dev);
return 0;
}
static int verify_start(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
struct fp_print_data *print;
struct fp_print_data_item *item;
G_DEBUG_HERE();
if (virt->state != STATE_IDLE)
return -1;
g_assert (virt->curr_uuid == NULL);
virt->state = STATE_VERIFY;
print = fpi_dev_get_verify_data(dev);
item = fpi_print_data_get_item(print);
/* We expecte a UUID, that means 36 bytes. */
g_assert(item->length == 36);
virt->curr_uuid = g_malloc(37);
virt->curr_uuid[36] = '\0';
memcpy(virt->curr_uuid, item->data, 36);
g_assert(g_uuid_string_is_valid (virt->curr_uuid));
send_status(dev);
fpi_drvcb_verify_started(dev, 0);
return 0;
}
static int verify_stop(struct fp_dev *dev, gboolean iterating)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
G_DEBUG_HERE();
if (virt->state != STATE_VERIFY)
return -1;
virt->state = STATE_IDLE;
g_free (virt->curr_uuid);
virt->curr_uuid = NULL;
send_status(dev);
fpi_drvcb_verify_stopped(dev);
return 0;
}
static int delete_finger(struct fp_dev *dev)
{
struct virt_dev *virt = FP_INSTANCE_DATA(dev);
struct fp_print_data *print;
struct fp_print_data_item *item;
G_DEBUG_HERE();
if (virt->state != STATE_IDLE)
return -1;
g_assert (virt->curr_uuid == NULL);
virt->state = STATE_DELETE;
print = fpi_dev_get_delete_data(dev);
item = fpi_print_data_get_item(print);
/* We expecte a UUID, that means 36 bytes. */
g_assert(item->length == 36);
virt->curr_uuid = g_malloc(37);
virt->curr_uuid[36] = '\0';
memcpy(virt->curr_uuid, item->data, 36);
g_assert(g_uuid_string_is_valid (virt->curr_uuid));
send_status(dev);
return 0;
}
struct fp_driver virtual_misdev_driver = {
.id = VIRTUAL_MIS_ID,
.name = FP_COMPONENT,
.full_name = "Virtual match-in-sensor device with internal storage",
.bus = BUS_TYPE_VIRTUAL,
.id_table.virtual_envvar = "FP_VIRTUAL_MISDEV",
.scan_type = FP_SCAN_TYPE_PRESS,
.open = dev_init,
.close = dev_deinit,
.enroll_start = enroll_start,
.enroll_stop = enroll_stop,
.verify_start = verify_start,
.verify_stop = verify_stop,
.delete_finger = delete_finger,
};

View File

@@ -93,15 +93,13 @@ struct fp_dev {
int nr_enroll_stages;
enum fp_bus_type bus;
union {
libusb_device_handle *usb;
const char *virtual_env;
int i2c;
} device;
/* FIXME: This will eventually have a bus type */
libusb_device_handle *udev;
/* 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 */
@@ -166,13 +164,7 @@ struct fp_img_dev {
/* fp_dscv_dev structure definition */
struct fp_dscv_dev {
enum fp_bus_type bus;
union {
struct libusb_device *usb;
const char *virtual_env;
char *spi_path;
} desc;
struct libusb_device *udev;
struct fp_driver *drv;
unsigned long driver_data;
uint32_t devtype;

View File

@@ -66,6 +66,7 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb call
{
struct fp_driver *drv;
struct fp_dev *dev;
libusb_device_handle *udevh;
int r;
g_return_val_if_fail(ddev != NULL, -ENODEV);
@@ -74,32 +75,20 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb call
drv = ddev->drv;
G_DEBUG_HERE();
r = libusb_open(ddev->udev, &udevh);
if (r < 0) {
fp_err("usb_open failed, error %d", r);
return r;
}
dev = g_malloc0(sizeof(*dev));
dev->drv = drv;
dev->bus = ddev->bus;
dev->udev = udevh;
dev->__enroll_stage = -1;
dev->state = DEV_STATE_INITIALIZING;
dev->open_cb = callback;
dev->open_cb_data = user_data;
switch (ddev->bus) {
case BUS_TYPE_USB:
r = libusb_open(ddev->desc.usb, &dev->device.usb);
if (r < 0) {
fp_err("usb_open failed, error %d", r);
g_free (dev);
return r;
}
break;
case BUS_TYPE_SPI:
/* TODO: Implement */
break;
case BUS_TYPE_VIRTUAL:
dev->device.virtual_env = ddev->desc.virtual_env;
break;
}
if (!drv->open) {
fpi_drvcb_open_complete(dev, 0);
return 0;
@@ -109,14 +98,7 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb call
r = drv->open(dev, ddev->driver_data);
if (r) {
fp_err("device initialisation failed, driver=%s", drv->name);
switch (ddev->bus) {
case BUS_TYPE_USB:
libusb_close(dev->device.usb);
case BUS_TYPE_SPI:
case BUS_TYPE_VIRTUAL:
/* Nothing to do (this might change for SPI) */
break;
}
libusb_close(udevh);
g_free(dev);
}
@@ -130,16 +112,7 @@ void fpi_drvcb_close_complete(struct fp_dev *dev)
BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
dev->state = DEV_STATE_DEINITIALIZED;
fpi_timeout_cancel_all_for_dev(dev);
switch (dev->bus) {
case BUS_TYPE_USB:
libusb_close(dev->device.usb);
case BUS_TYPE_SPI:
case BUS_TYPE_VIRTUAL:
/* Nothing to do (this might change for SPI) */
break;
}
libusb_close(dev->udev);
if (dev->close_cb)
dev->close_cb(dev, dev->close_cb_data);
g_free(dev);
@@ -719,6 +692,7 @@ API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
*
* 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)
{
@@ -747,14 +721,17 @@ API_EXPORTED int fp_async_delete_finger(struct fp_dev *dev,
}
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

@@ -38,4 +38,5 @@ void fpi_drvcb_verify_stopped(struct fp_dev *dev);
void fpi_drvcb_delete_complete(struct fp_dev *dev, int status);
#endif

View File

@@ -181,7 +181,7 @@ API_EXPORTED struct fp_driver **fprint_get_drivers (void)
return (struct fp_driver **) g_ptr_array_free (array, FALSE);
}
static struct fp_driver *find_supporting_usb_driver(libusb_device *udev,
static struct fp_driver *find_supporting_driver(libusb_device *udev,
const struct usb_id **usb_id, uint32_t *devtype)
{
int ret;
@@ -207,13 +207,10 @@ static struct fp_driver *find_supporting_usb_driver(libusb_device *udev,
uint32_t type = 0;
const struct usb_id *id;
if (drv->bus != BUS_TYPE_USB)
continue;
for (id = drv->id_table.usb; id->vendor; id++) {
for (id = drv->id_table; id->vendor; id++) {
if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) {
if (drv->usb_discover) {
int r = drv->usb_discover(&dsc, &type);
if (drv->discover) {
int r = drv->discover(&dsc, &type);
if (r < 0)
fp_err("%s discover failed, code %d", drv->name, r);
if (r <= 0)
@@ -249,81 +246,26 @@ static struct fp_driver *find_supporting_usb_driver(libusb_device *udev,
return best_drv;
}
static struct fp_dscv_dev *discover_usb_dev(libusb_device *udev)
static struct fp_dscv_dev *discover_dev(libusb_device *udev)
{
const struct usb_id *usb_id;
struct fp_driver *drv;
struct fp_dscv_dev *ddev;
uint32_t devtype;
drv = find_supporting_usb_driver(udev, &usb_id, &devtype);
drv = find_supporting_driver(udev, &usb_id, &devtype);
if (!drv)
return NULL;
ddev = g_malloc0(sizeof(*ddev));
ddev->drv = drv;
ddev->bus = BUS_TYPE_USB;
ddev->desc.usb = udev;
ddev->udev = udev;
ddev->driver_data = usb_id->driver_data;
ddev->devtype = devtype;
return ddev;
}
static void discover_usb_devs(GPtrArray *found_devices)
{
libusb_device *udev;
libusb_device **devs;
int r;
int i = 0;
r = libusb_get_device_list(fpi_usb_ctx, &devs);
if (r < 0) {
fp_err("couldn't enumerate USB devices, error %d", r);
return;
}
/* Check each device against each driver, temporarily storing successfully
* discovered devices in a GPtrArray. */
while ((udev = devs[i++]) != NULL) {
struct fp_dscv_dev *ddev = discover_usb_dev(udev);
if (!ddev)
continue;
/* discover_usb_dev() doesn't hold a reference to the udev,
* so increase the reference for ddev to hold this ref */
libusb_ref_device(udev);
g_ptr_array_add (found_devices, (gpointer) ddev);
}
libusb_free_device_list(devs, 1);
}
static void discover_virtual_devs(GPtrArray *found_devices)
{
GSList *elem;
for (elem = registered_drivers; elem; elem = g_slist_next(elem)) {
struct fp_driver *drv = elem->data;
struct fp_dscv_dev *ddev = NULL;
const gchar *var;
if (drv->bus != BUS_TYPE_VIRTUAL)
continue;
var = g_getenv (drv->id_table.virtual_envvar);
if (var == NULL)
continue;
ddev = g_malloc0(sizeof(*ddev));
ddev->drv = drv;
ddev->bus = BUS_TYPE_VIRTUAL;
ddev->desc.virtual_env = var;
ddev->devtype = 0;
g_ptr_array_add (found_devices, ddev);
}
}
/**
* fp_discover_devs:
*
@@ -337,25 +279,39 @@ static void discover_virtual_devs(GPtrArray *found_devices)
*/
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
{
GPtrArray *found_devices;
GPtrArray *tmparray;
libusb_device *udev;
libusb_device **devs;
int r;
int i = 0;
g_return_val_if_fail (registered_drivers != NULL, NULL);
found_devices = g_ptr_array_new ();
discover_usb_devs (found_devices);
discover_virtual_devs (found_devices);
/* Return NULL if no devices were found. */
if (found_devices->len == 0) {
g_ptr_array_free (found_devices, TRUE);
r = libusb_get_device_list(fpi_usb_ctx, &devs);
if (r < 0) {
fp_err("couldn't enumerate USB devices, error %d", r);
return NULL;
}
tmparray = g_ptr_array_new ();
/* Check each device against each driver, temporarily storing successfully
* discovered devices in a GPtrArray. */
while ((udev = devs[i++]) != NULL) {
struct fp_dscv_dev *ddev = discover_dev(udev);
if (!ddev)
continue;
/* discover_dev() doesn't hold a reference to the udev,
* so increase the reference for ddev to hold this ref */
libusb_ref_device(udev);
g_ptr_array_add (tmparray, (gpointer) ddev);
}
libusb_free_device_list(devs, 1);
/* Convert our temporary array into a standard NULL-terminated pointer
* array. */
g_ptr_array_add (found_devices, NULL);
return (struct fp_dscv_dev **) g_ptr_array_free (found_devices, FALSE);
g_ptr_array_add (tmparray, NULL);
return (struct fp_dscv_dev **) g_ptr_array_free (tmparray, FALSE);
}
/**
@@ -374,17 +330,7 @@ API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
return;
for (i = 0; devs[i]; i++) {
switch (devs[i]->bus) {
case BUS_TYPE_USB:
libusb_unref_device(devs[i]->desc.usb);
break;
case BUS_TYPE_SPI:
g_free(devs[i]->desc.spi_path);
break;
case BUS_TYPE_VIRTUAL:
/* Nothing to do */
break;
}
libusb_unref_device(devs[i]->udev);
g_free(devs[i]);
}
g_free(devs);
@@ -768,12 +714,10 @@ API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
*/
API_EXPORTED int fp_dev_supports_data_in_sensor(struct fp_dev *dev)
{
g_return_val_if_fail(dev, 0);
g_return_val_if_fail(dev->drv, 0);
return dev->drv->delete_finger != NULL;
}
/**
* fp_dev_get_img_width:
* @dev: the struct #fp_dev device

View File

@@ -67,37 +67,16 @@ enum fp_driver_type {
DRIVER_IMAGING = 1,
};
/**
* fp_bus_type:
* @BUS_TYPE_USB: USB device
* @BUS_TYPE_SPI: SPI device
* @BUS_TYPE_VIRTUAL: Virtual test bus
*
* The bus type of the device/driver.
*/
enum fp_bus_type {
BUS_TYPE_USB,
BUS_TYPE_SPI,
BUS_TYPE_VIRTUAL
};
struct fp_driver {
const uint16_t id;
const char *name;
const char *full_name;
enum fp_bus_type bus;
union {
const struct usb_id * const usb;
const char * const *i2c;
const char * virtual_envvar;
} id_table;
const struct usb_id * const id_table;
enum fp_driver_type type;
enum fp_scan_type scan_type;
/* Device operations */
int (*usb_discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype);
int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype);
int (*open)(struct fp_dev *dev, unsigned long driver_data);
void (*close)(struct fp_dev *dev);
int (*enroll_start)(struct fp_dev *dev);

View File

@@ -114,34 +114,7 @@ FP_INSTANCE_DATA (struct fp_dev *dev)
libusb_device_handle *
fpi_dev_get_usb_dev(struct fp_dev *dev)
{
g_assert (dev->bus == BUS_TYPE_USB);
return dev->device.usb;
}
/**
* fpi_dev_get_virtual_env:
* @dev: a struct #fp_dev
*
* Returns the value of the environment variable that is assicated with
* the virtual device.
*
* Returns: the value of the environment variable
*/
const char *
fpi_dev_get_virtual_env(struct fp_dev *dev)
{
g_assert (dev->bus == BUS_TYPE_VIRTUAL);
return dev->device.virtual_env;
}
int
fpi_dev_get_spi_dev(struct fp_dev *dev)
{
g_assert (dev->bus == BUS_TYPE_SPI);
return dev->device.i2c;
return dev->udev;
}
/**
@@ -181,7 +154,6 @@ fpi_dev_get_verify_data(struct fp_dev *dev)
* @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 *
@@ -189,3 +161,4 @@ fpi_dev_get_delete_data(struct fp_dev *dev)
{
return dev->delete_data;
}

View File

@@ -40,11 +40,10 @@ void fp_dev_set_instance_data (struct fp_dev *dev,
void *FP_INSTANCE_DATA (struct fp_dev *dev);
libusb_device_handle *fpi_dev_get_usb_dev(struct fp_dev *dev);
const char *fpi_dev_get_virtual_env(struct fp_dev *dev);
int fpi_dev_get_spi_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

@@ -28,7 +28,6 @@
#include <sys/time.h>
#include <glib.h>
#include <glib-unix.h>
#include <libusb.h>
/**
@@ -76,38 +75,64 @@
* for example.
*/
static GMainContext *fpi_main_ctx = NULL;
/* this is a singly-linked list of pending timers, sorted with the timer that
* is expiring soonest at the head. */
static GSList *active_timers = NULL;
/* notifiers for added or removed poll fds */
static fp_pollfd_added_cb fd_added_cb = NULL;
static fp_pollfd_removed_cb fd_removed_cb = NULL;
struct fpi_timeout {
struct timeval expiry;
fpi_timeout_fn callback;
struct fp_dev *dev;
void *data;
GSource *source;
char *name;
};
static void
fpi_timeout_destroy (gpointer data)
static int timeout_sort_fn(gconstpointer _a, gconstpointer _b)
{
fpi_timeout *timeout = data;
fpi_timeout *a = (fpi_timeout *) _a;
fpi_timeout *b = (fpi_timeout *) _b;
struct timeval *tv_a = &a->expiry;
struct timeval *tv_b = &b->expiry;
active_timers = g_slist_remove (active_timers, timeout);
if (timercmp(tv_a, tv_b, <))
return -1;
else if (timercmp(tv_a, tv_b, >))
return 1;
else
return 0;
}
static void
fpi_timeout_free(fpi_timeout *timeout)
{
if (timeout == NULL)
return;
g_free(timeout->name);
g_free(timeout);
}
static gboolean
fpi_timeout_wrapper_cb (gpointer data)
/**
* fpi_timeout_set_name:
* @timeout: a #fpi_timeout
* @name: the name to give the timeout
*
* Sets a name for a timeout, allowing that name to be printed
* along with any timeout related debug.
*/
void
fpi_timeout_set_name(fpi_timeout *timeout,
const char *name)
{
fpi_timeout *timeout = (fpi_timeout*) data;
g_return_if_fail (timeout != NULL);
g_return_if_fail (name != NULL);
g_return_if_fail (timeout->name == NULL);
timeout->callback (timeout->dev, timeout->data);
return G_SOURCE_REMOVE;
timeout->name = g_strdup(name);
}
/**
@@ -129,37 +154,43 @@ fpi_timeout_wrapper_cb (gpointer data)
*
* Returns: an #fpi_timeout structure
*/
fpi_timeout *
fpi_timeout_add(unsigned int msec,
fpi_timeout *fpi_timeout_add(unsigned int msec,
fpi_timeout_fn callback,
struct fp_dev *dev,
void *data)
{
struct timespec ts;
struct timeval add_msec;
fpi_timeout *timeout;
int r;
timeout = g_new0 (fpi_timeout, 1);
timeout->source = g_timeout_source_new (msec);
active_timers = g_slist_prepend (active_timers, timeout);
g_return_val_if_fail (dev != NULL, NULL);
g_source_set_callback (timeout->source, fpi_timeout_wrapper_cb, timeout, fpi_timeout_destroy);
g_source_attach (timeout->source, fpi_main_ctx);
fp_dbg("in %dms", msec);
return timeout;
r = clock_gettime(CLOCK_MONOTONIC, &ts);
if (r < 0) {
fp_err("failed to read monotonic clock, errno=%d", errno);
BUG();
return NULL;
}
/**
* fpi_timeout_set_name:
* @timeout: a #fpi_timeout
* @name: the name to give the timeout
*
* Sets a name for a timeout, allowing that name to be printed
* along with any timeout related debug.
*/
void
fpi_timeout_set_name(fpi_timeout *timeout,
const char *name)
{
g_source_set_name (timeout->source, name);
timeout = g_new0(fpi_timeout, 1);
timeout->callback = callback;
timeout->dev = dev;
timeout->data = data;
TIMESPEC_TO_TIMEVAL(&timeout->expiry, &ts);
/* calculate timeout expiry by adding delay to current monotonic clock */
timerclear(&add_msec);
add_msec.tv_sec = msec / 1000;
add_msec.tv_usec = (msec % 1000) * 1000;
timeradd(&timeout->expiry, &add_msec, &timeout->expiry);
active_timers = g_slist_insert_sorted(active_timers, timeout,
timeout_sort_fn);
return timeout;
}
/**
@@ -169,110 +200,81 @@ fpi_timeout_set_name(fpi_timeout *timeout,
* Cancels a timeout scheduled with fpi_timeout_add(), and frees the
* @timeout structure.
*/
void
fpi_timeout_cancel(fpi_timeout *timeout)
void fpi_timeout_cancel(fpi_timeout *timeout)
{
g_source_destroy (timeout->source);
G_DEBUG_HERE();
active_timers = g_slist_remove(active_timers, timeout);
fpi_timeout_free(timeout);
}
struct fpi_io_condition {
fpi_io_condition_fn callback;
int fd;
struct fp_dev *dev;
void *data;
GSource *source;
};
static gboolean
fpi_io_condition_wrapper_cb (int fd, GIOCondition cond, gpointer data)
/* 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
* is zero then it means the timeout has already expired and should be handled
* ASAP. */
static int get_next_timeout_expiry(struct timeval *out,
struct fpi_timeout **out_timeout)
{
fpi_io_condition *io_cond = data;
short events = 0;
struct timespec ts;
struct timeval tv;
struct fpi_timeout *next_timeout;
int r;
if (cond & G_IO_IN)
events |= POLL_IN;
if (cond & G_IO_OUT)
events |= POLL_OUT;
if (cond & G_IO_PRI)
events |= POLL_PRI;
if (cond & G_IO_ERR)
events |= POLL_ERR;
if (cond & G_IO_HUP)
events |= POLL_HUP;
if (active_timers == NULL)
return 0;
io_cond->callback (io_cond->dev, fd, cond, io_cond->data);
r = clock_gettime(CLOCK_MONOTONIC, &ts);
if (r < 0) {
fp_err("failed to read monotonic clock, errno=%d", errno);
return r;
}
TIMESPEC_TO_TIMEVAL(&tv, &ts);
return G_SOURCE_CONTINUE;
next_timeout = active_timers->data;
if (out_timeout)
*out_timeout = next_timeout;
if (timercmp(&tv, &next_timeout->expiry, >=)) {
if (next_timeout->name)
fp_dbg("first timeout '%s' already expired", next_timeout->name);
else
fp_dbg("first timeout already expired");
timerclear(out);
} else {
timersub(&next_timeout->expiry, &tv, out);
if (next_timeout->name)
fp_dbg("next timeout '%s' in %ld.%06lds", next_timeout->name,
out->tv_sec, out->tv_usec);
else
fp_dbg("next timeout in %ld.%06lds", out->tv_sec, out->tv_usec);
}
static void
fpi_io_condition_destroy (gpointer data)
{
fpi_io_condition *io_cond = data;
if (fd_removed_cb)
fd_removed_cb(io_cond->fd);
g_free (io_cond);
return 1;
}
fpi_io_condition *
fpi_io_condition_add(int fd,
short int events,
fpi_io_condition_fn callback,
struct fp_dev *dev,
void *data)
/* handle a timeout that has expired */
static void handle_timeout(struct fpi_timeout *timeout)
{
fpi_io_condition *io_cond;
GIOCondition cond = 0;
if (events & POLL_IN)
cond |= G_IO_IN;
if (events & POLL_OUT)
cond |= G_IO_OUT;
if (events & POLL_PRI)
cond |= G_IO_PRI;
if (events & POLL_ERR)
cond |= G_IO_ERR;
if (events & POLL_HUP)
cond |= G_IO_HUP;
io_cond = g_new0 (fpi_io_condition, 1);
io_cond->source = g_unix_fd_source_new (fd, cond);
io_cond->fd = fd;
io_cond->callback = callback;
io_cond->data = data;
io_cond->dev = dev;
g_source_set_callback (io_cond->source,
G_SOURCE_FUNC (fpi_io_condition_wrapper_cb),
io_cond,
fpi_io_condition_destroy);
g_source_attach (io_cond->source, fpi_main_ctx);
if (fd_added_cb)
fd_added_cb(fd, events);
return io_cond;
G_DEBUG_HERE();
timeout->callback(timeout->dev, timeout->data);
active_timers = g_slist_remove(active_timers, timeout);
fpi_timeout_free(timeout);
}
void
fpi_io_condition_set_name(fpi_io_condition *io_cond,
const char *name)
static int handle_timeouts(void)
{
g_source_set_name (io_cond->source, name);
}
struct timeval next_timeout_expiry;
struct fpi_timeout *next_timeout;
int r;
void
fpi_io_condition_remove(fpi_io_condition *io_cond)
{
g_source_destroy(io_cond->source);
}
r = get_next_timeout_expiry(&next_timeout_expiry, &next_timeout);
if (r <= 0)
return r;
static gboolean
dummy_cb (gpointer user_data)
{
return G_SOURCE_REMOVE;
if (!timerisset(&next_timeout_expiry))
handle_timeout(next_timeout);
return 0;
}
/**
@@ -288,22 +290,37 @@ dummy_cb (gpointer user_data)
*/
API_EXPORTED int fp_handle_events_timeout(struct timeval *timeout)
{
GSource *timeout_source;
struct timeval next_timeout_expiry;
struct timeval select_timeout;
struct fpi_timeout *next_timeout;
int r;
if (timeout->tv_sec == 0 && timeout->tv_usec == 0) {
g_main_context_iteration (fpi_main_ctx, FALSE);
r = get_next_timeout_expiry(&next_timeout_expiry, &next_timeout);
if (r < 0)
return r;
if (r) {
/* timer already expired? */
if (!timerisset(&next_timeout_expiry)) {
handle_timeout(next_timeout);
return 0;
}
/* Register a timeout on the mainloop and then run in blocking mode */
timeout_source = g_timeout_source_new (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
g_source_set_name (timeout_source, "fpi poll timeout");
g_source_set_callback (timeout_source, dummy_cb, NULL, NULL);
g_source_attach (timeout_source, fpi_main_ctx);
g_main_context_iteration (fpi_main_ctx, TRUE);
g_source_destroy (timeout_source);
/* choose the smallest of next URB timeout or user specified timeout */
if (timercmp(&next_timeout_expiry, timeout, <))
select_timeout = next_timeout_expiry;
else
select_timeout = *timeout;
} else {
select_timeout = *timeout;
}
return 0;
r = libusb_handle_events_timeout(fpi_usb_ctx, &select_timeout);
*timeout = select_timeout;
if (r < 0)
return r;
return handle_timeouts();
}
/**
@@ -333,37 +350,35 @@ API_EXPORTED int fp_handle_events(void)
*/
API_EXPORTED int fp_get_next_timeout(struct timeval *tv)
{
int timeout_;
struct timeval fprint_timeout = { 0, 0 };
struct timeval libusb_timeout = { 0, 0 };
int r_fprint;
int r_libusb;
g_return_val_if_fail (g_main_context_acquire (fpi_main_ctx), 0);
r_fprint = get_next_timeout_expiry(&fprint_timeout, NULL);
r_libusb = libusb_get_next_timeout(fpi_usb_ctx, &libusb_timeout);
g_main_context_query (fpi_main_ctx,
G_MININT,
&timeout_,
NULL,
0);
if (timeout_ < 0)
/* if we have no pending timeouts and the same is true for libusb,
* indicate that we have no pending timouts */
if (r_fprint <= 0 && r_libusb <= 0)
return 0;
tv->tv_sec = timeout_ / 1000;
tv->tv_usec = (timeout_ % 1000) * 1000;
/* if fprint have no pending timeouts return libusb timeout */
else if (r_fprint == 0)
*tv = libusb_timeout;
/* if libusb have no pending timeouts return fprint timeout */
else if (r_libusb == 0)
*tv = fprint_timeout;
/* otherwise return the smaller of the 2 timeouts */
else if (timercmp(&fprint_timeout, &libusb_timeout, <))
*tv = fprint_timeout;
else
*tv = libusb_timeout;
return 1;
}
typedef struct {
GSource source;
GSList *fds;
} fpi_libusb_source;
typedef struct {
int fd;
gpointer tag;
} fpi_libusb_fd;
static fpi_libusb_source *libusb_source = NULL;
/**
* fp_get_pollfds:
* @pollfds: output location for a list of pollfds. If non-%NULL, must be
@@ -379,52 +394,33 @@ static fpi_libusb_source *libusb_source = NULL;
*/
API_EXPORTED ssize_t fp_get_pollfds(struct fp_pollfd **pollfds)
{
gint timeout_;
GPollFD fds_static[16];
GPollFD *fds = fds_static;
gint n_fds;
int i;
const struct libusb_pollfd **usbfds;
const struct libusb_pollfd *usbfd;
struct fp_pollfd *ret;
ssize_t cnt = 0;
size_t i = 0;
g_return_val_if_fail (g_main_context_acquire (fpi_main_ctx), -1);
g_return_val_if_fail (fpi_usb_ctx != NULL, -EIO);
n_fds = g_main_context_query (fpi_main_ctx,
G_MININT,
&timeout_,
fds,
G_N_ELEMENTS (fds_static));
if (n_fds > G_N_ELEMENTS (fds_static)) {
fds = g_new0 (GPollFD, n_fds);
n_fds = g_main_context_query (fpi_main_ctx,
G_MININT,
&timeout_,
fds,
n_fds);
usbfds = libusb_get_pollfds(fpi_usb_ctx);
if (!usbfds) {
*pollfds = NULL;
return -EIO;
}
g_main_context_release (fpi_main_ctx);
while ((usbfd = usbfds[i++]) != NULL)
cnt++;
*pollfds = g_new0 (struct fp_pollfd, n_fds);
for (i = 0; i < n_fds; i++) {
(*pollfds)[i].fd = fds[i].fd;
if (fds[i].events & G_IO_IN)
(*pollfds)[i].events |= POLL_IN;
if (fds[i].events & G_IO_OUT)
(*pollfds)[i].events |= POLL_OUT;
if (fds[i].events & G_IO_PRI)
(*pollfds)[i].events |= POLL_PRI;
if (fds[i].events & G_IO_ERR)
(*pollfds)[i].events |= POLL_ERR;
if (fds[i].events & G_IO_HUP)
(*pollfds)[i].events |= POLL_HUP;
ret = g_malloc(sizeof(struct fp_pollfd) * cnt);
i = 0;
while ((usbfd = usbfds[i]) != NULL) {
ret[i].fd = usbfd->fd;
ret[i].events = usbfd->events;
i++;
}
if (fds != fds_static)
g_free (fds);
return n_fds;
*pollfds = ret;
return cnt;
}
/**
@@ -444,129 +440,30 @@ API_EXPORTED void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb,
static void add_pollfd(int fd, short events, void *user_data)
{
GIOCondition io_cond = 0;
fpi_libusb_fd *data;
gpointer tag;
if (events & POLL_IN)
io_cond |= G_IO_IN;
if (events & POLL_OUT)
io_cond |= G_IO_OUT;
if (events & POLL_PRI)
io_cond |= G_IO_PRI;
if (events & POLL_ERR)
io_cond |= G_IO_ERR;
if (events & POLL_HUP)
io_cond |= G_IO_HUP;
tag = g_source_add_unix_fd (&libusb_source->source, fd, io_cond);
data = g_new0 (fpi_libusb_fd, 1);
data->fd = fd;
data->tag = tag;
libusb_source->fds = g_slist_prepend (libusb_source->fds, data);
if (fd_added_cb)
fd_added_cb(fd, events);
}
static void remove_pollfd(int fd, void *user_data)
{
GSList *elem = g_slist_find_custom (libusb_source->fds, &fd, g_int_equal);
fpi_libusb_fd *item;
g_return_if_fail (elem != NULL);
item = (fpi_libusb_fd*) elem->data;
g_source_remove_unix_fd (&libusb_source->source, item->tag);
libusb_source->fds = g_slist_remove_link (libusb_source->fds, elem);
g_slist_free (elem);
g_free (item);
if (fd_removed_cb)
fd_removed_cb(fd);
}
static gboolean
fpi_libusb_prepare (GSource *source,
gint *timeout_)
{
struct timeval tv;
*timeout_ = -1;
if (libusb_get_next_timeout(fpi_usb_ctx, &tv) == 1) {
if (tv.tv_sec == 0 && tv.tv_usec == 0)
return TRUE;
*timeout_ = tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
return FALSE;
}
static gboolean
fpi_libusb_check (GSource *source)
{
/* Just call into libusb for every mainloop cycle */
return TRUE;
}
static gboolean
fpi_libusb_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
struct timeval zero_tv = { 0, 0 };
libusb_handle_events_timeout (fpi_usb_ctx, &zero_tv);
return G_SOURCE_CONTINUE;
}
static void
fpi_libusb_finalize (GSource *source)
{
fpi_libusb_source *fpi_source = (fpi_libusb_source*) source;
g_slist_free_full (fpi_source->fds, g_free);
}
GSourceFuncs libusb_source_funcs = {
.prepare = fpi_libusb_prepare,
.check = fpi_libusb_check,
.dispatch = fpi_libusb_dispatch,
.finalize = fpi_libusb_finalize,
};
void fpi_poll_init(void)
{
fpi_main_ctx = g_main_context_new ();
libusb_source = (fpi_libusb_source*) g_source_new (&libusb_source_funcs, sizeof(fpi_libusb_source));
g_source_set_name (&libusb_source->source, "libfprint internal libusb source");
g_source_attach (&libusb_source->source, fpi_main_ctx);
libusb_set_pollfd_notifiers(fpi_usb_ctx, add_pollfd, remove_pollfd, NULL);
}
void fpi_poll_exit(void)
{
g_source_destroy (&libusb_source->source);
libusb_source = NULL;
g_main_context_unref (fpi_main_ctx);
fpi_main_ctx = NULL;
g_slist_free_full(active_timers, (GDestroyNotify) fpi_timeout_free);
active_timers = NULL;
fd_added_cb = NULL;
fd_removed_cb = NULL;
libusb_set_pollfd_notifiers(fpi_usb_ctx, NULL, NULL, NULL);
}
void
fpi_timeout_cancel_all_for_dev(struct fp_dev *dev)
{
@@ -576,10 +473,13 @@ fpi_timeout_cancel_all_for_dev(struct fp_dev *dev)
l = active_timers;
while (l) {
fpi_timeout *cb_data = l->data;
struct fpi_timeout *timeout = l->data;
GSList *current = l;
l = l->next;
if (cb_data->dev == dev)
g_source_destroy (cb_data->source);
if (timeout->dev == dev) {
g_free (timeout);
active_timers = g_slist_delete_link (active_timers, current);
}
}
}

View File

@@ -48,34 +48,4 @@ void fpi_timeout_set_name(fpi_timeout *timeout,
const char *name);
void fpi_timeout_cancel(fpi_timeout *timeout);
/**
* fpi_io_condition_fn:
* @dev: the struct #fp_dev passed to fpi_io_condition_add()
* @fd: the registered file descriptor
* @events: The events that poll returend for the descriptor
* @data: the data passed to fpi_io_condition_add()
*
* The prototype of the callback function for fpi_io_condition_add().
* Note that structure will be free'ed when unregistering the condition.
*/
typedef void (*fpi_io_condition_fn)(struct fp_dev *dev, int fd, short int events, void *data);
/**
* fpi_io_cond:
*
* An opaque structure representing a pollable file descriptor and a
* callback function created with fpi_io_condition_add().
*/
typedef struct fpi_io_condition fpi_io_condition;
fpi_io_condition *fpi_io_condition_add(int fd,
short int events,
fpi_io_condition_fn callback,
struct fp_dev *dev,
void *data);
void fpi_io_condition_set_name(fpi_io_condition *io_cond,
const char *name);
void fpi_io_condition_remove(fpi_io_condition *io_cond);
#endif

View File

@@ -445,7 +445,6 @@ 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;
@@ -459,8 +458,8 @@ static void sync_delete_cb(struct fp_dev *dev, int result, void *user_data)
* @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.
* 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
*/
@@ -505,6 +504,9 @@ out:
return r;
}
struct sync_identify_data {
gboolean populated;
int result;

View File

@@ -31,11 +31,10 @@ static GList *insert_driver (GList *list,
{
int i;
for (i = 0; driver->id_table.usb[i].vendor != 0; i++) {
for (i = 0; driver->id_table[i].vendor != 0; i++) {
char *key;
key = g_strdup_printf ("%04x:%04x", driver->id_table.usb[i].vendor,
driver->id_table.usb[i].product);
key = g_strdup_printf ("%04x:%04x", driver->id_table[i].vendor, driver->id_table[i].product);
if (g_hash_table_lookup (printed, key) != NULL) {
g_free (key);

View File

@@ -40,8 +40,7 @@ static const struct usb_id blacklist_id_table[] = {
};
struct fp_driver whitelist = {
.bus = BUS_TYPE_USB,
.id_table.usb = whitelist_id_table,
.id_table = whitelist_id_table,
.full_name = "Hardcoded whitelist"
};
@@ -53,13 +52,13 @@ static void print_driver (struct fp_driver *driver)
num_printed = 0;
for (i = 0; driver->id_table.usb[i].vendor != 0; i++) {
for (i = 0; driver->id_table[i].vendor != 0; i++) {
char *key;
blacklist = 0;
for (j = 0; blacklist_id_table[j].vendor != 0; j++) {
if (driver->id_table.usb[i].vendor == blacklist_id_table[j].vendor &&
driver->id_table.usb[i].product == blacklist_id_table[j].product) {
if (driver->id_table[i].vendor == blacklist_id_table[j].vendor &&
driver->id_table[i].product == blacklist_id_table[j].product) {
blacklist = 1;
break;
}
@@ -67,8 +66,7 @@ static void print_driver (struct fp_driver *driver)
if (blacklist)
continue;
key = g_strdup_printf ("%04x:%04x", driver->id_table.usb[i].vendor,
driver->id_table.usb[i].product);
key = g_strdup_printf ("%04x:%04x", driver->id_table[i].vendor, driver->id_table[i].product);
if (g_hash_table_lookup (printed, key) != NULL) {
g_free (key);
@@ -80,12 +78,8 @@ static void print_driver (struct fp_driver *driver)
if (num_printed == 0)
printf ("# %s\n", driver->full_name);
printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n",
driver->id_table.usb[i].vendor,
driver->id_table.usb[i].product);
printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n",
driver->id_table.usb[i].vendor,
driver->id_table.usb[i].product, driver->full_name);
printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ATTRS{dev}==\"*\", TEST==\"power/control\", ATTR{power/control}=\"auto\"\n", driver->id_table[i].vendor, driver->id_table[i].product);
printf ("SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", ENV{LIBFPRINT_DRIVER}=\"%s\"\n", driver->id_table[i].vendor, driver->id_table[i].product, driver->full_name);
num_printed++;
}

View File

@@ -471,6 +471,7 @@ 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

@@ -1,18 +1,40 @@
libfprint_sources = [
'fp_internal.h',
'nbis-helpers.h',
'drivers_api.h',
'fpi-async.c',
'fpi-async.h',
'fpi-assembling.c',
'fpi-assembling.h',
'fpi-core.c',
'fpi-core.h',
'fpi-data.c',
'fpi-data.h',
'fpi-dev.c',
'fpi-dev.h',
'fpi-dev-img.c',
'fpi-dev-img.h',
'fpi-img.c',
'fpi-img.h',
'fpi-log.h',
'fpi-ssm.c',
'fpi-ssm.h',
'fpi-sync.c',
'fpi-poll.h',
'fpi-poll.c',
'fpi-usb.h',
'fpi-usb.c',
'drivers/driver_ids.h',
]
nbis_sources = [
'nbis/include/bozorth.h',
'nbis/include/bz_array.h',
'nbis/include/defs.h',
'nbis/include/lfs.h',
'nbis/include/log.h',
'nbis/include/morph.h',
'nbis/include/sunrast.h',
'nbis/bozorth3/bozorth3.c',
'nbis/bozorth3/bz_alloc.c',
'nbis/bozorth3/bz_drvrs.c',
@@ -52,15 +74,16 @@ aesx660 = false
aes3k = false
drivers_sources = []
drivers_cflags = []
foreach driver: drivers
if driver == 'upekts'
drivers_sources += [ 'drivers/upekts.c', 'drivers/upek_proto.c' ]
drivers_sources += [ 'drivers/upekts.c' ]
endif
if driver == 'upektc'
drivers_sources += [ 'drivers/upektc.c' ]
drivers_sources += [ 'drivers/upektc.c', 'drivers/upektc.h', 'drivers/upek_proto.c', 'drivers/upek_proto.h' ]
endif
if driver == 'upeksonly'
drivers_sources += [ 'drivers/upeksonly.c' ]
drivers_sources += [ 'drivers/upeksonly.c', 'drivers/upeksonly.h' ]
endif
if driver == 'uru4000'
drivers_sources += [ 'drivers/uru4000.c' ]
@@ -70,20 +93,20 @@ foreach driver: drivers
aeslib = true
endif
if driver == 'aes1660'
drivers_sources += [ 'drivers/aes1660.c' ]
drivers_sources += [ 'drivers/aes1660.c', 'drivers/aes1660.h' ]
aeslib = true
aesx660 = true
endif
if driver == 'aes2501'
drivers_sources += [ 'drivers/aes2501.c' ]
drivers_sources += [ 'drivers/aes2501.c', 'drivers/aes2501.h' ]
aeslib = true
endif
if driver == 'aes2550'
drivers_sources += [ 'drivers/aes2550.c' ]
drivers_sources += [ 'drivers/aes2550.c', 'drivers/aes2550.h' ]
aeslib = true
endif
if driver == 'aes2660'
drivers_sources += [ 'drivers/aes2660.c' ]
drivers_sources += [ 'drivers/aes2660.c', 'drivers/aes2660.h' ]
aeslib = true
aesx660 = true
endif
@@ -107,39 +130,43 @@ foreach driver: drivers
drivers_sources += [ 'drivers/vfs101.c' ]
endif
if driver == 'vfs301'
drivers_sources += [ 'drivers/vfs301.c', 'drivers/vfs301_proto.c' ]
drivers_sources += [ 'drivers/vfs301.c', 'drivers/vfs301_proto.c', 'drivers/vfs301_proto.h', 'drivers/vfs301_proto_fragments.h' ]
endif
if driver == 'vfs5011'
drivers_sources += [ 'drivers/vfs5011.c' ]
drivers_sources += [ 'drivers/vfs5011.c', 'drivers/vfs5011_proto.h' ]
endif
if driver == 'upektc_img'
drivers_sources += [ 'drivers/upektc_img.c', 'drivers/upek_proto.c' ]
drivers_sources += [ 'drivers/upektc_img.c', 'drivers/upektc_img.h', 'drivers/upek_proto.c', 'drivers/upek_proto.h' ]
endif
if driver == 'etes603'
drivers_sources += [ 'drivers/etes603.c' ]
endif
if driver == 'vfs0050'
drivers_sources += [ 'drivers/vfs0050.c' ]
drivers_sources += [ 'drivers/vfs0050.c', 'drivers/vfs0050.h' ]
endif
if driver == 'elan'
drivers_sources += [ 'drivers/elan.c' ]
drivers_sources += [ 'drivers/elan.c', 'drivers/elan.h' ]
endif
if driver == 'virtual_imgdev'
drivers_sources += [ 'drivers/virtual_imgdev.c' ]
endif
if driver == 'virtual_misdev'
drivers_sources += [ 'drivers/virtual_misdev.c' ]
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
drivers_sources += [ 'drivers/aeslib.c' ]
drivers_sources += [ 'drivers/aeslib.c', 'drivers/aeslib.h' ]
endif
if aesx660
drivers_sources += ['drivers/aesx660.c' ]
drivers_sources += ['drivers/aesx660.c', 'drivers/aesx660.h' ]
endif
if aes3k
drivers_sources += ['drivers/aes3k.c' ]
drivers_sources += ['drivers/aes3k.c', 'drivers/aes3k.h' ]
endif
other_sources = []
@@ -164,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', 'virtual_imgdev', 'virtual_misdev' ]
primitive_drivers = [ 'upekts', 'virtual_misdev' ]
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