2019-07-29 13:55:27 +00:00
|
|
|
/*
|
|
|
|
* 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-byte-reader.h"
|
|
|
|
|
|
|
|
#include "synaptics.h"
|
|
|
|
#include "bmkt_message.h"
|
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
G_DEFINE_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FP_TYPE_DEVICE)
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
static const FpIdEntry id_table[] = {
|
|
|
|
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xBD, },
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
|
2019-07-29 13:55:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
cmd_recieve_cb (FpiUsbTransfer *transfer,
|
2019-11-19 20:13:11 +00:00
|
|
|
FpDevice *device,
|
|
|
|
gpointer user_data,
|
|
|
|
GError *error)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
|
|
|
|
SynCmdMsgCallback callback = user_data;
|
|
|
|
int res;
|
|
|
|
bmkt_msg_resp_t msg_resp;
|
|
|
|
bmkt_response_t resp;
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
/* NOTE: assumes timeout should never happen for receiving. */
|
|
|
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = bmkt_parse_message_header (&transfer->buffer[SENSOR_FW_REPLY_HEADER_LEN],
|
|
|
|
transfer->actual_length - SENSOR_FW_REPLY_HEADER_LEN,
|
|
|
|
&msg_resp);
|
|
|
|
if (res != BMKT_SUCCESS)
|
|
|
|
{
|
|
|
|
g_warning ("Corrupted message received");
|
|
|
|
fpi_ssm_mark_failed (transfer->ssm,
|
|
|
|
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Special case events */
|
|
|
|
if (msg_resp.msg_id == BMKT_EVT_FINGER_REPORT)
|
|
|
|
{
|
|
|
|
if (msg_resp.payload_len != 1)
|
|
|
|
{
|
|
|
|
g_warning ("Corrupted finger report received");
|
|
|
|
fpi_ssm_mark_failed (transfer->ssm,
|
|
|
|
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg_resp.payload[0] == 0x01)
|
|
|
|
{
|
|
|
|
self->finger_on_sensor = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
self->finger_on_sensor = FALSE;
|
|
|
|
if (self->cmd_complete_on_removal)
|
|
|
|
{
|
|
|
|
fpi_ssm_mark_completed (transfer->ssm);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fp_dbg ("Finger is now %s the sensor", self->finger_on_sensor ? "on" : "off");
|
|
|
|
|
|
|
|
/* XXX: Call callback!?! */
|
|
|
|
}
|
|
|
|
|
|
|
|
res = bmkt_parse_message_payload (&msg_resp, &resp);
|
|
|
|
if (res != BMKT_SUCCESS)
|
|
|
|
{
|
|
|
|
g_warning ("Could not parse message payload: %i", res);
|
|
|
|
fpi_ssm_mark_failed (transfer->ssm,
|
|
|
|
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Special cancellation handling */
|
|
|
|
if (resp.response_id == BMKT_RSP_CANCEL_OP_OK || resp.response_id == BMKT_RSP_CANCEL_OP_FAIL)
|
|
|
|
{
|
|
|
|
if (resp.response_id == BMKT_RSP_CANCEL_OP_OK)
|
|
|
|
{
|
|
|
|
fp_dbg ("Received cancellation success resonse");
|
|
|
|
fpi_ssm_mark_failed (transfer->ssm,
|
|
|
|
g_error_new_literal (G_IO_ERROR,
|
|
|
|
G_IO_ERROR_CANCELLED,
|
|
|
|
"Device reported cancellation of operation"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fp_dbg ("Cancellation failed, this should not happen");
|
|
|
|
fpi_ssm_mark_failed (transfer->ssm,
|
|
|
|
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg_resp.seq_num == 0)
|
|
|
|
{
|
|
|
|
/* XXX: Should we really abort the command on general error?
|
|
|
|
* The original code did not! */
|
|
|
|
if (msg_resp.msg_id == BMKT_RSP_GENERAL_ERROR)
|
|
|
|
{
|
|
|
|
guint16 err;
|
|
|
|
|
|
|
|
/* XXX: It is weird that this is big endian. */
|
|
|
|
err = FP_READ_UINT16_BE (msg_resp.payload);
|
|
|
|
|
|
|
|
fp_warn ("Received General Error %d from the sensor", (guint) err);
|
|
|
|
fpi_ssm_mark_failed (transfer->ssm,
|
|
|
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
|
2019-11-25 20:23:31 +00:00
|
|
|
"Received general error %u from device",
|
|
|
|
(guint) err));
|
2019-11-19 20:13:11 +00:00
|
|
|
//fpi_ssm_jump_to_state (transfer->ssm, fpi_ssm_get_cur_state (transfer->ssm));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fp_dbg ("Received message with 0 sequence number 0x%02x, ignoring!",
|
|
|
|
msg_resp.msg_id);
|
|
|
|
fpi_ssm_next_state (transfer->ssm);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We should only ever have one command running, and the sequence num needs
|
|
|
|
* to match. */
|
|
|
|
if (msg_resp.seq_num != self->cmd_seq_num)
|
|
|
|
{
|
|
|
|
fp_warn ("Got unexpected sequence number from device, %d instead of %d",
|
|
|
|
msg_resp.seq_num,
|
|
|
|
self->cmd_seq_num);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (callback)
|
|
|
|
callback (self, &resp, NULL);
|
|
|
|
|
|
|
|
/* Callback may have queued a follow up command, then we need
|
|
|
|
* to restart the SSM. If not, we'll finish/wait for interrupt
|
|
|
|
* depending on resp.complete. */
|
|
|
|
if (self->cmd_pending_transfer)
|
|
|
|
fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_SEND_PENDING);
|
2019-12-09 06:12:54 +00:00
|
|
|
else if (!resp.complete || self->cmd_complete_on_removal)
|
2019-11-19 20:13:11 +00:00
|
|
|
fpi_ssm_next_state (transfer->ssm); /* SYNAPTICS_CMD_WAIT_INTERRUPT */
|
|
|
|
else
|
|
|
|
fpi_ssm_mark_completed (transfer->ssm);
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cmd_interrupt_cb (FpiUsbTransfer *transfer,
|
2019-11-19 20:13:11 +00:00
|
|
|
FpDevice *device,
|
|
|
|
gpointer user_data,
|
|
|
|
GError *error)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
g_debug ("interrupt transfer done");
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
|
|
{
|
|
|
|
g_error_free (error);
|
|
|
|
fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_GET_RESP);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
g_clear_pointer (&error, g_error_free);
|
|
|
|
|
|
|
|
if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING || error)
|
|
|
|
fpi_ssm_next_state (transfer->ssm);
|
|
|
|
else
|
|
|
|
fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_interrupt_cb, NULL);
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
synaptics_cmd_run_state (FpiSsm *ssm,
|
2019-11-20 17:05:46 +00:00
|
|
|
FpDevice *dev)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-26 20:23:42 +00:00
|
|
|
FpiUsbTransfer *transfer;
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
|
|
|
|
|
|
|
|
switch (fpi_ssm_get_cur_state (ssm))
|
|
|
|
{
|
|
|
|
case SYNAPTICS_CMD_SEND_PENDING:
|
|
|
|
if (self->cmd_pending_transfer)
|
|
|
|
{
|
|
|
|
self->cmd_pending_transfer->ssm = ssm;
|
|
|
|
fpi_usb_transfer_submit (self->cmd_pending_transfer,
|
|
|
|
1000,
|
|
|
|
NULL,
|
|
|
|
fpi_ssm_usb_transfer_cb,
|
|
|
|
NULL);
|
2019-11-26 20:23:42 +00:00
|
|
|
self->cmd_pending_transfer = NULL;
|
2019-11-19 20:13:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fpi_ssm_next_state (ssm);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SYNAPTICS_CMD_GET_RESP:
|
|
|
|
transfer = fpi_usb_transfer_new (dev);
|
|
|
|
transfer->ssm = ssm;
|
|
|
|
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, MAX_TRANSFER_LEN);
|
|
|
|
fpi_usb_transfer_submit (transfer,
|
|
|
|
5000,
|
|
|
|
NULL,
|
|
|
|
cmd_recieve_cb,
|
2019-11-20 17:05:46 +00:00
|
|
|
fpi_ssm_get_data (ssm));
|
2019-11-19 20:13:11 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SYNAPTICS_CMD_WAIT_INTERRUPT:
|
|
|
|
transfer = fpi_usb_transfer_new (dev);
|
|
|
|
transfer->ssm = ssm;
|
|
|
|
fpi_usb_transfer_fill_interrupt (transfer, USB_EP_INTERRUPT, USB_INTERRUPT_DATA_SIZE);
|
|
|
|
fpi_usb_transfer_submit (transfer,
|
|
|
|
0,
|
|
|
|
self->interrupt_cancellable,
|
|
|
|
cmd_interrupt_cb,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SYNAPTICS_CMD_SEND_ASYNC:
|
|
|
|
transfer = fpi_usb_transfer_new (dev);
|
|
|
|
transfer->ssm = ssm;
|
|
|
|
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN);
|
|
|
|
transfer->buffer[0] = SENSOR_CMD_ASYNCMSG_READ;
|
|
|
|
fpi_usb_transfer_submit (transfer,
|
|
|
|
1000,
|
|
|
|
NULL,
|
|
|
|
fpi_ssm_usb_transfer_cb,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SYNAPTICS_CMD_RESTART:
|
|
|
|
fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_SEND_PENDING);
|
|
|
|
break;
|
|
|
|
}
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-20 17:05:46 +00:00
|
|
|
cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
|
2019-11-20 17:05:46 +00:00
|
|
|
SynCmdMsgCallback callback = fpi_ssm_get_data (ssm);
|
2019-11-19 20:13:11 +00:00
|
|
|
|
|
|
|
self->cmd_ssm = NULL;
|
|
|
|
|
|
|
|
/* Notify about the SSM failure from here instead. */
|
2020-01-16 18:08:10 +00:00
|
|
|
if (error || self->cmd_complete_on_removal)
|
|
|
|
callback (self, NULL, error);
|
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
self->cmd_complete_on_removal = FALSE;
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cmd_forget_cb (FpiUsbTransfer *transfer,
|
2019-11-19 20:13:11 +00:00
|
|
|
FpDevice *device,
|
|
|
|
gpointer user_data,
|
|
|
|
GError *error)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
g_warning ("Async command sending failed: %s", error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_debug ("Async command sent successfully");
|
|
|
|
}
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
synaptics_sensor_cmd (FpiDeviceSynaptics *self,
|
2019-11-19 20:13:11 +00:00
|
|
|
gint seq_num,
|
|
|
|
guint8 msg_id,
|
|
|
|
const guint8 * payload,
|
|
|
|
gssize payload_len,
|
|
|
|
SynCmdMsgCallback callback)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-26 20:23:42 +00:00
|
|
|
FpiUsbTransfer *transfer;
|
2019-11-19 20:13:11 +00:00
|
|
|
guint8 real_seq_num;
|
|
|
|
gint msg_len;
|
|
|
|
gint res;
|
|
|
|
|
|
|
|
/* callback may be NULL in two cases:
|
|
|
|
* - seq_num == -1
|
|
|
|
* - a state machine is already running, continued command */
|
|
|
|
g_assert (payload || payload_len == 0);
|
|
|
|
|
|
|
|
/* seq_num of 0 means a normal command, -1 means the current commands
|
|
|
|
* sequence number should not be udpated (i.e. second async command which
|
|
|
|
* may only be a cancellation currently). */
|
|
|
|
if (seq_num <= 0)
|
|
|
|
{
|
|
|
|
self->last_seq_num = MAX (1, self->last_seq_num + 1);
|
|
|
|
real_seq_num = self->last_seq_num;
|
|
|
|
if (seq_num == 0)
|
|
|
|
self->cmd_seq_num = self->last_seq_num;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
real_seq_num = seq_num;
|
|
|
|
self->last_seq_num = real_seq_num;
|
|
|
|
}
|
|
|
|
g_debug ("sequence number is %d", real_seq_num);
|
|
|
|
|
|
|
|
/* We calculate the exact length here (we could also just create a larger
|
|
|
|
* buffer instead and check the result of bmkt_compose_message. */
|
|
|
|
msg_len = BMKT_MESSAGE_HEADER_LEN + payload_len;
|
|
|
|
|
|
|
|
/* Send out the command */
|
|
|
|
transfer = fpi_usb_transfer_new (FP_DEVICE (self));
|
|
|
|
transfer->short_is_error = TRUE;
|
|
|
|
fpi_usb_transfer_fill_bulk (transfer,
|
|
|
|
USB_EP_REQUEST,
|
|
|
|
msg_len + SENSOR_FW_CMD_HEADER_LEN);
|
|
|
|
|
|
|
|
/* MIS sensors send ACE commands encapsulated in FW commands*/
|
|
|
|
transfer->buffer[0] = SENSOR_CMD_ACE_COMMAND;
|
|
|
|
res = bmkt_compose_message (&transfer->buffer[1],
|
|
|
|
&msg_len, msg_id,
|
|
|
|
real_seq_num,
|
|
|
|
payload_len,
|
|
|
|
payload);
|
|
|
|
g_assert (res == BMKT_SUCCESS);
|
|
|
|
g_assert (msg_len + SENSOR_FW_CMD_HEADER_LEN == transfer->length);
|
|
|
|
|
|
|
|
/* Special case for async command sending (should only be used for
|
|
|
|
* cancellation). */
|
|
|
|
if (seq_num == -1)
|
|
|
|
{
|
|
|
|
g_assert (callback == NULL);
|
|
|
|
|
|
|
|
/* We just send and forget here. */
|
|
|
|
fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_forget_cb, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Command should be send using the state machine. */
|
|
|
|
g_assert (self->cmd_pending_transfer == NULL);
|
|
|
|
|
|
|
|
self->cmd_pending_transfer = g_steal_pointer (&transfer);
|
|
|
|
|
|
|
|
if (self->cmd_ssm)
|
|
|
|
{
|
|
|
|
/* Continued command, we already have an SSM with a callback.
|
|
|
|
* There is nothing to do in this case, the command will be
|
|
|
|
* sent automatically. */
|
|
|
|
g_assert (callback == NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Start of a new command, create the state machine. */
|
|
|
|
g_assert (callback != NULL);
|
|
|
|
|
|
|
|
self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self),
|
|
|
|
synaptics_cmd_run_state,
|
2019-11-20 17:05:46 +00:00
|
|
|
SYNAPTICS_CMD_NUM_STATES);
|
|
|
|
fpi_ssm_set_data (self->cmd_ssm, callback, NULL);
|
2019-11-19 20:13:11 +00:00
|
|
|
|
|
|
|
fpi_ssm_start (self->cmd_ssm, cmd_ssm_done);
|
|
|
|
}
|
|
|
|
}
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
parse_print_data (GVariant *data,
|
|
|
|
guint8 *finger,
|
|
|
|
const guint8 **user_id,
|
2019-12-03 18:36:26 +00:00
|
|
|
gsize *user_id_len)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
g_autoptr(GVariant) user_id_var = NULL;
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
g_return_val_if_fail (data != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (finger != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (user_id != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (user_id_len != NULL, FALSE);
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
*user_id = NULL;
|
|
|
|
*user_id_len = 0;
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
if (!g_variant_check_format_string (data, "(y@ay)", FALSE))
|
|
|
|
return FALSE;
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
g_variant_get (data,
|
|
|
|
"(y@ay)",
|
|
|
|
finger,
|
|
|
|
&user_id_var);
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
*user_id = g_variant_get_fixed_array (user_id_var, user_id_len, 1);
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
if (*user_id_len == 0 || *user_id_len > BMKT_MAX_USER_ID_LEN)
|
|
|
|
return FALSE;
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
if (*user_id_len <= 0 || *user_id[0] == ' ')
|
|
|
|
return FALSE;
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
return TRUE;
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
list_msg_cb (FpiDeviceSynaptics *self,
|
|
|
|
bmkt_response_t *resp,
|
|
|
|
GError *error)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
bmkt_enroll_templates_resp_t *get_enroll_templates_resp;
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
{
|
2019-11-25 17:35:50 +00:00
|
|
|
g_clear_pointer (&self->list_result, g_ptr_array_unref);
|
2019-11-19 20:13:11 +00:00
|
|
|
fpi_device_list_complete (FP_DEVICE (self), NULL, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
get_enroll_templates_resp = &resp->response.enroll_templates_resp;
|
|
|
|
|
|
|
|
switch (resp->response_id)
|
|
|
|
{
|
|
|
|
case BMKT_RSP_QUERY_FAIL:
|
|
|
|
if (resp->result == BMKT_FP_DATABASE_EMPTY)
|
|
|
|
{
|
|
|
|
fp_info ("Database is empty");
|
|
|
|
|
|
|
|
fpi_device_list_complete (FP_DEVICE (self),
|
|
|
|
g_steal_pointer (&self->list_result),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fp_info ("Failed to query enrolled users: %d", resp->result);
|
2019-11-25 17:35:50 +00:00
|
|
|
g_clear_pointer (&self->list_result, g_ptr_array_unref);
|
2019-11-19 20:13:11 +00:00
|
|
|
fpi_device_list_complete (FP_DEVICE (self),
|
|
|
|
NULL,
|
|
|
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
2019-11-25 20:23:31 +00:00
|
|
|
"Failed to query enrolled users: %d",
|
|
|
|
resp->result));
|
2019-11-19 20:13:11 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BMKT_RSP_QUERY_RESPONSE_COMPLETE:
|
|
|
|
fp_info ("Query complete!");
|
|
|
|
|
|
|
|
fpi_device_list_complete (FP_DEVICE (self),
|
|
|
|
g_steal_pointer (&self->list_result),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BMKT_RSP_TEMPLATE_RECORDS_REPORT:
|
|
|
|
|
|
|
|
for (int n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
|
|
|
|
{
|
|
|
|
GVariant *data = NULL;
|
|
|
|
GVariant *uid = NULL;
|
|
|
|
FpPrint *print;
|
|
|
|
gchar *userid;
|
|
|
|
|
|
|
|
if (get_enroll_templates_resp->templates[n].user_id_len == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
fp_info ("![query %d of %d] template %d: status=0x%x, userId=%s, fingerId=%d",
|
|
|
|
get_enroll_templates_resp->query_sequence,
|
|
|
|
get_enroll_templates_resp->total_query_messages,
|
|
|
|
n,
|
|
|
|
get_enroll_templates_resp->templates[n].template_status,
|
|
|
|
get_enroll_templates_resp->templates[n].user_id,
|
|
|
|
get_enroll_templates_resp->templates[n].finger_id);
|
|
|
|
|
2019-12-03 18:36:26 +00:00
|
|
|
userid = (gchar *) get_enroll_templates_resp->templates[n].user_id;
|
2019-11-19 20:13:11 +00:00
|
|
|
|
|
|
|
print = fp_print_new (FP_DEVICE (self));
|
|
|
|
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
|
|
|
|
get_enroll_templates_resp->templates[n].user_id,
|
|
|
|
get_enroll_templates_resp->templates[n].user_id_len,
|
|
|
|
1);
|
|
|
|
data = g_variant_new ("(y@ay)",
|
|
|
|
get_enroll_templates_resp->templates[n].finger_id,
|
|
|
|
uid);
|
|
|
|
|
2019-12-16 21:45:00 +00:00
|
|
|
fpi_print_set_type (print, FPI_PRINT_RAW);
|
2019-11-19 20:13:11 +00:00
|
|
|
fpi_print_set_device_stored (print, TRUE);
|
2019-12-18 11:03:42 +00:00
|
|
|
g_object_set (print, "fpi-data", data, NULL);
|
2019-11-19 20:13:11 +00:00
|
|
|
g_object_set (print, "description", get_enroll_templates_resp->templates[n].user_id, NULL);
|
|
|
|
|
|
|
|
/* The format has 24 bytes at the start and some dashes in the right places */
|
|
|
|
if (g_str_has_prefix (userid, "FP1-") && strlen (userid) >= 24 &&
|
|
|
|
userid[12] == '-' && userid[14] == '-' && userid[23] == '-')
|
|
|
|
{
|
|
|
|
g_autofree gchar *copy = g_strdup (userid);
|
|
|
|
gint32 date_ymd;
|
|
|
|
GDate *date = NULL;
|
|
|
|
gint32 finger;
|
|
|
|
gchar *username;
|
|
|
|
/* Try to parse information from the string. */
|
|
|
|
|
|
|
|
copy[12] = '\0';
|
|
|
|
date_ymd = g_ascii_strtod (copy + 4, NULL);
|
|
|
|
if (date_ymd > 0)
|
|
|
|
date = g_date_new_dmy (date_ymd % 100,
|
|
|
|
(date_ymd / 100) % 100,
|
|
|
|
date_ymd / 10000);
|
|
|
|
else
|
|
|
|
date = g_date_new ();
|
|
|
|
|
|
|
|
fp_print_set_enroll_date (print, date);
|
|
|
|
g_date_free (date);
|
|
|
|
|
|
|
|
copy[14] = '\0';
|
|
|
|
finger = g_ascii_strtoll (copy + 13, NULL, 16);
|
|
|
|
fp_print_set_finger (print, finger);
|
|
|
|
|
|
|
|
/* We ignore the next chunk, it is just random data.
|
|
|
|
* Then comes the username; nobody is the default if the metadata
|
|
|
|
* is unknown */
|
|
|
|
username = copy + 24;
|
|
|
|
if (strlen (username) > 0 && g_strcmp0 (username, "nobody") != 0)
|
|
|
|
fp_print_set_username (print, username);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_ptr_array_add (self->list_result, g_object_ref_sink (print));
|
|
|
|
}
|
|
|
|
|
|
|
|
synaptics_sensor_cmd (self,
|
|
|
|
self->cmd_seq_num,
|
|
|
|
BMKT_CMD_GET_NEXT_QUERY_RESPONSE,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
list (FpDevice *device)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
G_DEBUG_HERE ();
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
self->list_result = g_ptr_array_new_with_free_func (g_object_unref);
|
|
|
|
synaptics_sensor_cmd (self, 0, BMKT_CMD_GET_TEMPLATE_RECORDS, NULL, 0, list_msg_cb);
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
verify_msg_cb (FpiDeviceSynaptics *self,
|
|
|
|
bmkt_response_t *resp,
|
|
|
|
GError *error)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpDevice *device = FP_DEVICE (self);
|
|
|
|
bmkt_verify_resp_t *verify_resp;
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
{
|
2019-12-24 00:01:04 +00:00
|
|
|
fpi_device_verify_complete (device, error);
|
2019-11-19 20:13:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (resp == NULL && self->cmd_complete_on_removal)
|
|
|
|
{
|
2019-12-24 00:01:04 +00:00
|
|
|
fpi_device_verify_complete (device, NULL);
|
2019-11-19 20:13:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-25 17:37:12 +00:00
|
|
|
g_assert (resp != NULL);
|
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
verify_resp = &resp->response.verify_resp;
|
|
|
|
|
|
|
|
switch (resp->response_id)
|
|
|
|
{
|
|
|
|
case BMKT_RSP_VERIFY_READY:
|
|
|
|
fp_info ("Place Finger on the Sensor!");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BMKT_RSP_CAPTURE_COMPLETE:
|
|
|
|
fp_info ("Fingerprint image capture complete!");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BMKT_RSP_VERIFY_FAIL:
|
|
|
|
if(resp->result == BMKT_SENSOR_STIMULUS_ERROR)
|
|
|
|
{
|
|
|
|
fp_dbg ("delaying retry error until after finger removal!");
|
|
|
|
self->cmd_complete_on_removal = TRUE;
|
2020-01-16 18:04:09 +00:00
|
|
|
fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL,
|
|
|
|
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
|
2019-11-19 20:13:11 +00:00
|
|
|
}
|
|
|
|
else if (resp->result == BMKT_FP_NO_MATCH)
|
|
|
|
{
|
|
|
|
fp_dbg ("delaying match failure until after finger removal!");
|
|
|
|
self->cmd_complete_on_removal = TRUE;
|
2020-01-16 18:04:09 +00:00
|
|
|
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL);
|
2019-11-19 20:13:11 +00:00
|
|
|
}
|
2020-01-16 18:09:20 +00:00
|
|
|
else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
|
2019-11-19 20:13:11 +00:00
|
|
|
{
|
|
|
|
fp_info ("Print is not in database");
|
|
|
|
fpi_device_verify_complete (device,
|
|
|
|
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fp_warn ("Verify has failed: %d", resp->result);
|
2019-12-24 00:01:04 +00:00
|
|
|
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL);
|
|
|
|
fpi_device_verify_complete (device, NULL);
|
2019-11-19 20:13:11 +00:00
|
|
|
}
|
|
|
|
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);
|
2019-12-24 00:01:04 +00:00
|
|
|
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, NULL, NULL);
|
|
|
|
fpi_device_verify_complete (device, NULL);
|
2019-11-19 20:13:11 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
verify (FpDevice *device)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
|
|
|
|
FpPrint *print = NULL;
|
|
|
|
|
|
|
|
g_autoptr(GVariant) data = NULL;
|
|
|
|
guint8 finger;
|
|
|
|
const guint8 *user_id;
|
|
|
|
gsize user_id_len = 0;
|
|
|
|
|
|
|
|
fpi_device_get_verify_data (device, &print);
|
|
|
|
|
2019-12-18 11:03:42 +00:00
|
|
|
g_object_get (print, "fpi-data", &data, NULL);
|
2019-11-19 20:13:11 +00:00
|
|
|
g_debug ("data is %p", data);
|
|
|
|
if (!parse_print_data (data, &finger, &user_id, &user_id_len))
|
|
|
|
{
|
|
|
|
fpi_device_verify_complete (device,
|
|
|
|
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_DEBUG_HERE ();
|
|
|
|
|
|
|
|
synaptics_sensor_cmd (self, 0, BMKT_CMD_VERIFY_USER, user_id, user_id_len, verify_msg_cb);
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
enroll_msg_cb (FpiDeviceSynaptics *self,
|
|
|
|
bmkt_response_t *resp,
|
|
|
|
GError *error)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpDevice *device = FP_DEVICE (self);
|
|
|
|
bmkt_enroll_resp_t *enroll_resp;
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
fpi_device_enroll_complete (device, NULL, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
enroll_resp = &resp->response.enroll_resp;
|
|
|
|
|
|
|
|
switch (resp->response_id)
|
|
|
|
{
|
|
|
|
case BMKT_RSP_ENROLL_READY:
|
|
|
|
{
|
|
|
|
self->enroll_stage = 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:
|
|
|
|
{
|
|
|
|
gint done_stages;
|
|
|
|
fp_info ("Enrollment is %d %% ", enroll_resp->progress);
|
|
|
|
|
|
|
|
done_stages = (enroll_resp->progress * ENROLL_SAMPLES + 99) / 100;
|
|
|
|
if (enroll_resp->progress < 100)
|
|
|
|
done_stages = MIN (done_stages, ENROLL_SAMPLES - 1);
|
|
|
|
|
|
|
|
/* Emit a retry error if there has been no discernable
|
|
|
|
* progress. Some firmware revisions report more required
|
|
|
|
* touches. */
|
|
|
|
if (self->enroll_stage == done_stages)
|
|
|
|
{
|
|
|
|
fpi_device_enroll_progress (device,
|
|
|
|
done_stages,
|
|
|
|
NULL,
|
|
|
|
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
|
|
|
|
}
|
|
|
|
|
|
|
|
while (self->enroll_stage < done_stages)
|
|
|
|
{
|
|
|
|
self->enroll_stage += 1;
|
|
|
|
fpi_device_enroll_progress (device, self->enroll_stage, NULL, NULL);
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
if (resp->result == BMKT_FP_DATABASE_FULL)
|
|
|
|
{
|
|
|
|
fpi_device_enroll_complete (device,
|
|
|
|
NULL,
|
|
|
|
fpi_device_error_new (FP_DEVICE_ERROR_DATA_FULL));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fpi_device_enroll_complete (device,
|
|
|
|
NULL,
|
|
|
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
2019-11-25 20:23:31 +00:00
|
|
|
"Enrollment failed (%d)",
|
|
|
|
resp->result));
|
2019-11-19 20:13:11 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case BMKT_RSP_ENROLL_OK:
|
|
|
|
{
|
|
|
|
FpPrint *print = NULL;
|
|
|
|
|
|
|
|
fp_info ("Enrollment was successful!");
|
|
|
|
|
|
|
|
fpi_device_get_enroll_data (device, &print);
|
|
|
|
|
|
|
|
fpi_device_enroll_complete (device, g_object_ref (print), NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define TEMPLATE_ID_SIZE 20
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
enroll (FpDevice *device)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
|
|
|
|
FpPrint *print = NULL;
|
|
|
|
GVariant *data = NULL;
|
|
|
|
GVariant *uid = NULL;
|
|
|
|
const gchar *username;
|
|
|
|
guint finger;
|
2019-11-27 15:59:23 +00:00
|
|
|
g_autofree gchar *user_id = NULL;
|
2019-11-19 20:13:11 +00:00
|
|
|
gssize user_id_len;
|
|
|
|
g_autofree guint8 *payload = NULL;
|
|
|
|
const GDate *date;
|
|
|
|
gint y, m, d;
|
|
|
|
gint32 rand_id = 0;
|
|
|
|
|
|
|
|
fpi_device_get_enroll_data (device, &print);
|
|
|
|
|
|
|
|
G_DEBUG_HERE ();
|
|
|
|
|
|
|
|
date = fp_print_get_enroll_date (print);
|
|
|
|
if (date && g_date_valid (date))
|
|
|
|
{
|
2019-11-27 15:50:54 +00:00
|
|
|
y = g_date_get_year (date);
|
|
|
|
m = g_date_get_month (date);
|
|
|
|
d = g_date_get_day (date);
|
2019-11-19 20:13:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
y = 0;
|
|
|
|
m = 0;
|
|
|
|
d = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
username = fp_print_get_username (print);
|
|
|
|
if (!username)
|
|
|
|
username = "nobody";
|
|
|
|
|
|
|
|
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
|
|
|
rand_id = 0;
|
|
|
|
else
|
|
|
|
rand_id = g_random_int ();
|
|
|
|
|
|
|
|
user_id = g_strdup_printf ("FP1-%04d%02d%02d-%X-%08X-%s",
|
|
|
|
y, m, d,
|
|
|
|
fp_print_get_finger (print),
|
|
|
|
rand_id,
|
|
|
|
username);
|
|
|
|
|
|
|
|
user_id_len = strlen (user_id);
|
|
|
|
user_id_len = MIN (BMKT_MAX_USER_ID_LEN, user_id_len);
|
|
|
|
|
|
|
|
/* We currently always use finger 1 from the devices piont of view */
|
|
|
|
finger = 1;
|
|
|
|
|
|
|
|
uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
|
|
|
|
user_id,
|
|
|
|
user_id_len,
|
|
|
|
1);
|
|
|
|
data = g_variant_new ("(y@ay)",
|
|
|
|
finger,
|
|
|
|
uid);
|
|
|
|
|
2019-12-16 21:45:00 +00:00
|
|
|
fpi_print_set_type (print, FPI_PRINT_RAW);
|
2019-11-19 20:13:11 +00:00
|
|
|
fpi_print_set_device_stored (print, TRUE);
|
2019-12-18 11:03:42 +00:00
|
|
|
g_object_set (print, "fpi-data", data, NULL);
|
2019-11-19 20:13:11 +00:00
|
|
|
g_object_set (print, "description", user_id, NULL);
|
|
|
|
|
|
|
|
g_debug ("user_id: %s, finger: %d", user_id, finger);
|
|
|
|
|
|
|
|
payload = g_malloc0 (user_id_len + 2);
|
|
|
|
|
|
|
|
/* Backup options are not supported for Prometheus */
|
|
|
|
payload[0] = 0;
|
|
|
|
payload[1] = finger;
|
|
|
|
memcpy (payload + 2, user_id, user_id_len);
|
|
|
|
|
|
|
|
synaptics_sensor_cmd (self, 0, BMKT_CMD_ENROLL_USER, payload, user_id_len + 2, enroll_msg_cb);
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
delete_msg_cb (FpiDeviceSynaptics *self,
|
|
|
|
bmkt_response_t *resp,
|
|
|
|
GError *error)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpDevice *device = FP_DEVICE (self);
|
|
|
|
bmkt_del_user_resp_t *del_user_resp;
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
fpi_device_delete_complete (device, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
del_user_resp = &resp->response.del_user_resp;
|
|
|
|
|
|
|
|
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);
|
|
|
|
if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
|
|
|
|
fpi_device_delete_complete (device,
|
|
|
|
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
|
|
|
else
|
|
|
|
fpi_device_delete_complete (device,
|
|
|
|
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BMKT_RSP_DEL_USER_FP_OK:
|
|
|
|
fp_info ("Successfully deleted enrolled user");
|
|
|
|
fpi_device_delete_complete (device, NULL);
|
|
|
|
break;
|
|
|
|
}
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
delete_print (FpDevice *device)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
|
|
|
|
FpPrint *print = NULL;
|
|
|
|
|
|
|
|
g_autoptr(GVariant) data = NULL;
|
|
|
|
guint8 finger;
|
|
|
|
const guint8 *user_id;
|
|
|
|
gsize user_id_len = 0;
|
|
|
|
g_autofree guint8 *payload = NULL;
|
|
|
|
|
|
|
|
fpi_device_get_delete_data (device, &print);
|
|
|
|
|
2019-12-18 11:03:42 +00:00
|
|
|
g_object_get (print, "fpi-data", &data, NULL);
|
2019-11-19 20:13:11 +00:00
|
|
|
g_debug ("data is %p", data);
|
|
|
|
if (!parse_print_data (data, &finger, &user_id, &user_id_len))
|
|
|
|
{
|
|
|
|
fpi_device_delete_complete (device,
|
|
|
|
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_DEBUG_HERE ();
|
|
|
|
|
|
|
|
payload = g_malloc0 (1 + user_id_len);
|
|
|
|
payload[0] = finger;
|
|
|
|
memcpy (payload + 1, user_id, user_id_len);
|
|
|
|
|
|
|
|
synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_USER_FP, payload, user_id_len + 1, delete_msg_cb);
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
dev_probe (FpDevice *device)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
|
|
|
|
GUsbDevice *usb_dev;
|
2019-11-28 19:34:20 +00:00
|
|
|
|
|
|
|
g_autoptr(FpiUsbTransfer) transfer = NULL;
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiByteReader reader;
|
|
|
|
GError *error = NULL;
|
|
|
|
guint16 status;
|
|
|
|
const guint8 *data;
|
|
|
|
gboolean read_ok = TRUE;
|
|
|
|
g_autofree gchar *serial = NULL;
|
|
|
|
|
|
|
|
G_DEBUG_HERE ();
|
|
|
|
|
|
|
|
/* Claim usb interface */
|
|
|
|
usb_dev = fpi_device_get_usb_device (device);
|
|
|
|
if (!g_usb_device_open (usb_dev, &error))
|
|
|
|
{
|
|
|
|
fpi_device_probe_complete (device, NULL, NULL, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-05 14:48:57 +00:00
|
|
|
if (!g_usb_device_reset (usb_dev, &error))
|
2019-11-28 19:35:33 +00:00
|
|
|
goto err_close;
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-12-05 14:48:57 +00:00
|
|
|
if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
|
2019-11-19 20:13:11 +00:00
|
|
|
goto err_close;
|
|
|
|
|
|
|
|
/* TODO: Do not do this synchronous. */
|
|
|
|
transfer = fpi_usb_transfer_new (device);
|
|
|
|
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN);
|
|
|
|
transfer->short_is_error = TRUE;
|
|
|
|
transfer->buffer[0] = SENSOR_CMD_GET_VERSION;
|
|
|
|
if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
|
|
|
|
goto err_close;
|
|
|
|
|
2019-11-28 19:34:20 +00:00
|
|
|
g_clear_pointer (&transfer, fpi_usb_transfer_unref);
|
2019-11-19 20:13:11 +00:00
|
|
|
transfer = fpi_usb_transfer_new (device);
|
|
|
|
fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, 40);
|
|
|
|
if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
|
|
|
|
goto err_close;
|
|
|
|
|
|
|
|
fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length);
|
|
|
|
|
|
|
|
if (!fpi_byte_reader_get_uint16_le (&reader, &status))
|
|
|
|
{
|
|
|
|
g_warning ("Transfer in response to version query was too short");
|
|
|
|
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
|
|
|
goto err_close;
|
|
|
|
}
|
|
|
|
if (status != 0)
|
|
|
|
{
|
|
|
|
g_warning ("Device responded with error: %d", status);
|
|
|
|
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
|
|
|
goto err_close;
|
|
|
|
}
|
|
|
|
|
|
|
|
read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_time);
|
|
|
|
read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_num);
|
|
|
|
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_major);
|
|
|
|
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_minor);
|
|
|
|
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.target);
|
|
|
|
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.product);
|
|
|
|
|
|
|
|
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.silicon_rev);
|
|
|
|
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.formal_release);
|
|
|
|
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.platform);
|
|
|
|
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.patch);
|
|
|
|
if (fpi_byte_reader_get_data (&reader, sizeof (self->mis_version.serial_number), &data))
|
|
|
|
memcpy (self->mis_version.serial_number, data, sizeof (self->mis_version.serial_number));
|
|
|
|
else
|
|
|
|
read_ok = FALSE;
|
|
|
|
read_ok &= fpi_byte_reader_get_uint16_le (&reader, &self->mis_version.security);
|
|
|
|
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.iface);
|
|
|
|
read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.device_type);
|
|
|
|
|
|
|
|
if (!read_ok)
|
|
|
|
{
|
|
|
|
g_warning ("Transfer in response to verison query was too short");
|
|
|
|
error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
|
|
|
|
goto err_close;
|
|
|
|
}
|
|
|
|
|
|
|
|
fp_dbg ("Build Time: %d", self->mis_version.build_time);
|
|
|
|
fp_dbg ("Build Num: %d", self->mis_version.build_num);
|
|
|
|
fp_dbg ("Version: %d.%d", self->mis_version.version_major, self->mis_version.version_minor);
|
|
|
|
fp_dbg ("Target: %d", self->mis_version.target);
|
|
|
|
fp_dbg ("Product: %d", self->mis_version.product);
|
|
|
|
|
|
|
|
|
|
|
|
/* We need at least firmware version 10.1, and for 10.1 build 2989158 */
|
|
|
|
if (self->mis_version.version_major < 10 ||
|
|
|
|
self->mis_version.version_minor < 1 ||
|
|
|
|
(self->mis_version.version_major == 10 &&
|
|
|
|
self->mis_version.version_minor == 1 &&
|
|
|
|
self->mis_version.build_num < 2989158))
|
|
|
|
{
|
|
|
|
fp_warn ("Firmware version %d.%d with build number %d is unsupported",
|
|
|
|
self->mis_version.version_major,
|
|
|
|
self->mis_version.version_minor,
|
|
|
|
self->mis_version.build_num);
|
|
|
|
|
|
|
|
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
2019-11-25 20:23:31 +00:00
|
|
|
"Unsupported firmware version "
|
|
|
|
"(%d.%d with build number %d)",
|
|
|
|
self->mis_version.version_major,
|
|
|
|
self->mis_version.version_minor,
|
|
|
|
self->mis_version.build_num);
|
2019-11-19 20:13:11 +00:00
|
|
|
goto err_close;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This is the same as the serial_number from above, hex encoded and somewhat reordered */
|
|
|
|
/* Should we add in more, e.g. the chip revision? */
|
|
|
|
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
|
|
|
|
serial = g_strdup ("emulated-device");
|
|
|
|
else
|
|
|
|
serial = g_usb_device_get_string_descriptor (usb_dev,
|
|
|
|
g_usb_device_get_serial_number_index (usb_dev),
|
|
|
|
&error);
|
|
|
|
|
|
|
|
g_usb_device_close (usb_dev, NULL);
|
|
|
|
|
|
|
|
fpi_device_probe_complete (device, serial, NULL, error);
|
|
|
|
|
|
|
|
return;
|
2019-07-29 13:55:27 +00:00
|
|
|
|
|
|
|
err_close:
|
2019-11-19 20:13:11 +00:00
|
|
|
g_usb_device_close (usb_dev, NULL);
|
|
|
|
fpi_device_probe_complete (device, NULL, NULL, error);
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
fps_init_msg_cb (FpiDeviceSynaptics *self,
|
|
|
|
bmkt_response_t *resp,
|
|
|
|
GError *error)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
fpi_device_open_complete (FP_DEVICE (self), error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* BMKT_OPERATION_DENIED is returned if the sensor is already initialized */
|
|
|
|
if (resp->result == BMKT_SUCCESS || resp->result == BMKT_OPERATION_DENIED)
|
|
|
|
{
|
|
|
|
fpi_device_open_complete (FP_DEVICE (self), NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Initializing fingerprint sensor failed with %d!", resp->result);
|
|
|
|
fpi_device_open_complete (FP_DEVICE (self),
|
|
|
|
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
|
|
|
}
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
2019-10-31 07:05:43 +00:00
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
fps_deinit_cb (FpiDeviceSynaptics *self,
|
|
|
|
bmkt_response_t *resp,
|
|
|
|
GError *error)
|
2019-10-31 07:05:43 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
/* Release usb interface */
|
|
|
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), 0, 0, &error);
|
|
|
|
|
|
|
|
g_clear_object (&self->interrupt_cancellable);
|
|
|
|
|
|
|
|
if (!error)
|
|
|
|
{
|
|
|
|
switch (resp->response_id)
|
|
|
|
{
|
|
|
|
case BMKT_RSP_POWER_DOWN_READY:
|
|
|
|
fp_info ("Fingerprint sensor ready to be powered down");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BMKT_RSP_POWER_DOWN_FAIL:
|
|
|
|
fp_info ("Failed to go to power down mode: %d", resp->result);
|
|
|
|
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
2019-11-25 20:23:31 +00:00
|
|
|
"Power down failed: %d", resp->result);
|
2019-11-19 20:13:11 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fpi_device_close_complete (FP_DEVICE (self), error);
|
2019-10-31 07:05:43 +00:00
|
|
|
}
|
2019-07-29 13:55:27 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
dev_init (FpDevice *device)
|
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
|
|
|
|
GError *error = NULL;
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
G_DEBUG_HERE ();
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
self->interrupt_cancellable = g_cancellable_new ();
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
if (!g_usb_device_reset (fpi_device_get_usb_device (device), &error))
|
|
|
|
goto error;
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
/* Claim usb interface */
|
|
|
|
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error))
|
|
|
|
goto error;
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
synaptics_sensor_cmd (self, 0, BMKT_CMD_FPS_INIT, NULL, 0, fps_init_msg_cb);
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
return;
|
2019-07-29 13:55:27 +00:00
|
|
|
|
|
|
|
error:
|
2019-11-19 20:13:11 +00:00
|
|
|
fpi_device_open_complete (FP_DEVICE (self), error);
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
dev_exit (FpDevice *device)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
G_DEBUG_HERE ();
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
synaptics_sensor_cmd (self, 0, BMKT_CMD_POWER_DOWN_NOTIFY, NULL, 0, fps_deinit_cb);
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
cancel (FpDevice *dev)
|
2019-07-29 13:55:27 +00:00
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
/* We just send out a cancel command and hope for the best. */
|
|
|
|
synaptics_sensor_cmd (self, -1, BMKT_CMD_CANCEL_OP, NULL, 0, NULL);
|
2019-07-29 13:55:27 +00:00
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
/* Cancel any current interrupt transfer (resulting us to go into
|
|
|
|
* response reading mode again); then create a new cancellable
|
|
|
|
* for the next transfers. */
|
|
|
|
g_cancellable_cancel (self->interrupt_cancellable);
|
|
|
|
g_clear_object (&self->interrupt_cancellable);
|
|
|
|
self->interrupt_cancellable = g_cancellable_new ();
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
fpi_device_synaptics_init (FpiDeviceSynaptics *self)
|
|
|
|
{
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-19 20:13:11 +00:00
|
|
|
fpi_device_synaptics_class_init (FpiDeviceSynapticsClass *klass)
|
|
|
|
{
|
|
|
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
|
|
|
|
|
|
|
dev_class->id = FP_COMPONENT;
|
|
|
|
dev_class->full_name = SYNAPTICS_DRIVER_FULLNAME;
|
|
|
|
|
|
|
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
|
|
|
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
|
|
|
dev_class->id_table = id_table;
|
|
|
|
dev_class->nr_enroll_stages = ENROLL_SAMPLES;
|
|
|
|
|
|
|
|
dev_class->open = dev_init;
|
|
|
|
dev_class->close = dev_exit;
|
|
|
|
dev_class->probe = dev_probe;
|
|
|
|
dev_class->verify = verify;
|
|
|
|
dev_class->enroll = enroll;
|
|
|
|
dev_class->delete = delete_print;
|
|
|
|
dev_class->cancel = cancel;
|
|
|
|
dev_class->list = list;
|
2019-07-29 13:55:27 +00:00
|
|
|
}
|