Merge tag 'v1.90.5' into tod

Tag 1.90.5

Git-EVTag-v0-SHA512: 05650e2a6cf2290542936271b140e79015f56e35fbffc4677e37bf30963b2a38b49eb699db80cee6677ff348ea9e8548514a9f1e06a767269e44d7fac3334c45
This commit is contained in:
Marco Trevisan (Treviño)
2020-12-03 01:32:45 +01:00
58 changed files with 3425 additions and 589 deletions
+1 -3
View File
@@ -135,10 +135,8 @@ generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
size_t bytes)
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
unsigned char *data;
data = g_malloc (bytes);
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, bytes, g_free);
fpi_usb_transfer_fill_bulk (transfer, EP_IN, bytes);
transfer->ssm = ssm;
transfer->short_is_error = TRUE;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
+2 -2
View File
@@ -197,12 +197,12 @@ process_strip_data (FpiSsm *ssm, FpImageDevice *dev,
if (data[0] != AES2550_EDATA_MAGIC)
{
fp_dbg ("Bogus magic: %.2x\n", (int) (data[0]));
fp_dbg ("Bogus magic: %.2x", (int) (data[0]));
return FALSE;
}
len = data[1] * 256 + data[2];
if (len != (AES2550_STRIP_SIZE - 3))
fp_dbg ("Bogus frame len: %.4x\n", len);
fp_dbg ("Bogus frame len: %.4x", len);
stripe = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); /* 4 bits per pixel */
stripe->delta_x = (int8_t) data[6];
stripe->delta_y = -(int8_t) data[7];
+4
View File
@@ -106,7 +106,9 @@ static struct aes_regwrite init_reqs[] = {
{ 0x9e, 0x53 }, /* clear challenge word bits */
{ 0x9f, 0x6b }, /* set some challenge word bits */
{ 0, 0 },
};
static struct aes_regwrite capture_reqs[] = {
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
@@ -155,4 +157,6 @@ fpi_device_aes3500_class_init (FpiDeviceAes3500Class *klass)
aes_class->enlarge_factor = ENLARGE_FACTOR;
aes_class->init_reqs = init_reqs;
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
aes_class->capture_reqs = capture_reqs;
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
}
+62 -12
View File
@@ -42,7 +42,10 @@
typedef struct
{
GCancellable *img_trf_cancel;
/* This is used both as a flag that we are in a capture operation
* and for cancellation.
*/
GCancellable *img_capture_cancel;
} FpiDeviceAes3kPrivate;
#define CTRL_TIMEOUT 1000
@@ -76,12 +79,16 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
{
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (device);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
unsigned char *ptr = transfer->buffer;
FpImage *tmp;
FpImage *img;
int i;
/* Image capture operation is finished (error/completed) */
g_clear_object (&priv->img_capture_cancel);
if (error)
{
if (g_error_matches (error,
@@ -95,6 +102,7 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
}
fpi_image_device_session_error (dev, error);
return;
}
fpi_image_device_report_finger_status (dev, TRUE);
@@ -118,11 +126,10 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device,
fpi_image_device_image_captured (dev, img);
/* FIXME: rather than assuming finger has gone, we should poll regs until
* it really has, then restart the capture */
* it really has. */
fpi_image_device_report_finger_status (dev, FALSE);
/* Note: We always restart the transfer, it may already be cancelled though. */
do_capture (dev);
/* Note: The transfer is re-started when we switch to the AWAIT_FINGER_ON state. */
}
static void
@@ -137,27 +144,51 @@ do_capture (FpImageDevice *dev)
fpi_usb_transfer_fill_bulk (img_trf, EP_IN, cls->data_buflen);
img_trf->short_is_error = TRUE;
fpi_usb_transfer_submit (g_steal_pointer (&img_trf), 0,
priv->img_trf_cancel,
priv->img_capture_cancel,
img_cb, NULL);
}
static void
capture_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
{
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
if (result)
{
g_clear_object (&priv->img_capture_cancel);
fpi_image_device_session_error (dev, result);
return;
}
/* FIXME: we never cancel a pending capture. So we are likely leaving the
* hardware in a bad state should we abort the capture operation and the
* user does not touch the device.
* But, we don't know how we might cancel, so just leave it as is. */
do_capture (dev);
}
static void
do_capture_start (FpImageDevice *dev)
{
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
aes_write_regv (dev, cls->capture_reqs, cls->capture_reqs_len, capture_reqs_cb, NULL);
}
static void
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
{
fpi_image_device_activate_complete (dev, result);
if (!result)
do_capture (dev);
}
static void
aes3k_dev_activate (FpImageDevice *dev)
{
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
g_assert (!priv->img_trf_cancel);
priv->img_trf_cancel = g_cancellable_new ();
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
}
@@ -167,8 +198,26 @@ aes3k_dev_deactivate (FpImageDevice *dev)
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
/* Deactivation always finishes from the cancellation handler */
g_cancellable_cancel (priv->img_trf_cancel);
/* If a capture is running, then deactivation finishes from the cancellation handler */
if (priv->img_capture_cancel)
g_cancellable_cancel (priv->img_capture_cancel);
else
fpi_image_device_deactivate_complete (dev, NULL);
}
static void
aes3k_dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
{
g_assert (!priv->img_capture_cancel);
priv->img_capture_cancel = g_cancellable_new ();
do_capture_start (dev);
}
}
static void
@@ -213,6 +262,7 @@ fpi_device_aes3k_class_init (FpiDeviceAes3kClass *klass)
img_class->img_open = aes3k_dev_init;
img_class->img_close = aes3k_dev_deinit;
img_class->activate = aes3k_dev_activate;
img_class->change_state = aes3k_dev_change_state;
img_class->deactivate = aes3k_dev_deactivate;
/* Extremely low due to low image quality. */
+2
View File
@@ -57,4 +57,6 @@ struct _FpiDeviceAes3kClass
gsize data_buflen; /* buffer length of usb bulk transfer */
struct aes_regwrite *init_reqs; /* initial values sent to device */
gsize init_reqs_len;
struct aes_regwrite *capture_reqs; /* capture values sent to device */
gsize capture_reqs_len;
};
+4
View File
@@ -103,7 +103,9 @@ static struct aes_regwrite init_reqs[] = {
{ 0x9e, 0x53 }, /* clear challenge word bits */
{ 0x9f, 0x6b }, /* set some challenge word bits */
{ 0, 0 },
};
static struct aes_regwrite capture_reqs[] = {
{ 0x80, 0x00 },
{ 0x81, 0x00 },
{ 0, 0 },
@@ -152,4 +154,6 @@ fpi_device_aes4000_class_init (FpiDeviceAes4000Class *klass)
aes_class->enlarge_factor = ENLARGE_FACTOR;
aes_class->init_reqs = init_reqs;
aes_class->init_reqs_len = G_N_ELEMENTS (init_reqs);
aes_class->capture_reqs = capture_reqs;
aes_class->capture_reqs_len = G_N_ELEMENTS (capture_reqs);
}
+21 -20
View File
@@ -54,6 +54,7 @@ static void complete_deactivation (FpImageDevice *dev);
#define CALIBRATE_DATA_LEN 4
#define FINGER_DET_DATA_LEN 4
FP_GNUC_ACCESS (read_only, 3, 4)
static void
aesX660_send_cmd_timeout (FpiSsm *ssm,
FpDevice *_dev,
@@ -70,6 +71,7 @@ aesX660_send_cmd_timeout (FpiSsm *ssm,
fpi_usb_transfer_submit (transfer, timeout, NULL, callback, NULL);
}
FP_GNUC_ACCESS (read_only, 3, 4)
static void
aesX660_send_cmd (FpiSsm *ssm,
FpDevice *dev,
@@ -89,13 +91,12 @@ aesX660_read_response (FpiSsm *ssm,
FpiUsbTransferCallback callback)
{
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
unsigned char *data;
GCancellable *cancel = NULL;
if (cancellable)
cancel = fpi_device_get_cancellable (_dev);
data = g_malloc (buf_len);
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, buf_len, NULL);
fpi_usb_transfer_fill_bulk (transfer, EP_IN, buf_len);
transfer->ssm = ssm;
transfer->short_is_error = short_is_error;
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, cancel, callback, NULL);
@@ -116,7 +117,7 @@ aesX660_read_calibrate_data_cb (FpiUsbTransfer *transfer,
/* Calibrate response was read correctly? */
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE)
{
fp_dbg ("Bogus calibrate response: %.2x\n", data[0]);
fp_dbg ("Bogus calibrate response: %.2x", data[0]);
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Bogus calibrate "
@@ -155,14 +156,14 @@ finger_det_read_fd_data_cb (FpiUsbTransfer *transfer,
if (error)
{
fp_dbg ("Failed to read FD data\n");
fp_dbg ("Failed to read FD data");
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE)
{
fp_dbg ("Bogus FD response: %.2x\n", data[0]);
fp_dbg ("Bogus FD response: %.2x", data[0]);
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Bogus FD response %.2x",
@@ -177,7 +178,7 @@ finger_det_read_fd_data_cb (FpiUsbTransfer *transfer,
}
else
{
fp_dbg ("Wait for finger returned %.2x as result\n",
fp_dbg ("Wait for finger returned %.2x as result",
data[AESX660_FINGER_PRESENT_OFFSET]);
fpi_ssm_jump_to_state (transfer->ssm, FINGER_DET_SEND_FD_CMD);
}
@@ -405,7 +406,7 @@ capture_read_stripe_data_cb (FpiUsbTransfer *transfer,
g_byte_array_set_size (priv->stripe_packet, 0);
}
fp_dbg ("finger %s\n", finger_missing ? "missing" : "present");
fp_dbg ("finger %s", finger_missing ? "missing" : "present");
if (finger_missing)
fpi_ssm_next_state (transfer->ssm);
@@ -440,7 +441,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
break;
case CAPTURE_SET_IDLE:
fp_dbg ("Got %lu frames\n", priv->strips_len);
fp_dbg ("Got %lu frames", priv->strips_len);
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
capture_set_idle_cmd_cb);
break;
@@ -513,19 +514,19 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (error)
{
fp_dbg ("read_id cmd failed\n");
fp_dbg ("read_id cmd failed");
fpi_ssm_mark_failed (transfer->ssm, error);
return;
}
/* ID was read correctly */
if (data[0] == 0x07)
{
fp_dbg ("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x\n",
fp_dbg ("Sensor device id: %.2x%2x, bcdDevice: %.2x.%.2x, init status: %.2x",
data[4], data[3], data[5], data[6], data[7]);
}
else
{
fp_dbg ("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]);
fp_dbg ("Bogus read ID response: %.2x", data[AESX660_RESPONSE_TYPE_OFFSET]);
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Bogus read ID response %.2x",
@@ -553,7 +554,7 @@ activate_read_id_cb (FpiUsbTransfer *transfer, FpDevice *device,
break;
default:
fp_dbg ("Failed to init device! init status: %.2x\n", data[7]);
fp_dbg ("Failed to init device! init status: %.2x", data[7]);
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Failed to init device %.2x",
@@ -570,11 +571,11 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
FpiDeviceAesX660Private *priv = fpi_device_aes_x660_get_instance_private (self);
unsigned char *data = transfer->buffer;
fp_dbg ("read_init_cb\n");
fp_dbg ("read_init_cb");
if (error)
{
fp_dbg ("read_init transfer status: %s, actual_len: %d\n", error->message,
fp_dbg ("read_init transfer status: %s, actual_len: %d", error->message,
(gint) transfer->actual_length);
fpi_ssm_mark_failed (transfer->ssm, error);
return;
@@ -582,7 +583,7 @@ activate_read_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
/* ID was read correctly */
if (data[0] != 0x42 || data[3] != 0x01)
{
fp_dbg ("Bogus read init response: %.2x %.2x\n", data[0],
fp_dbg ("Bogus read init response: %.2x %.2x", data[0],
data[3]);
fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -614,13 +615,13 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
{
case ACTIVATE_SET_IDLE:
priv->init_seq_idx = 0;
fp_dbg ("Activate: set idle\n");
fp_dbg ("Activate: set idle");
aesX660_send_cmd (ssm, _dev, set_idle_cmd, sizeof (set_idle_cmd),
fpi_ssm_usb_transfer_cb);
break;
case ACTIVATE_SEND_READ_ID_CMD:
fp_dbg ("Activate: read ID\n");
fp_dbg ("Activate: read ID");
aesX660_send_cmd (ssm, _dev, read_id_cmd, sizeof (read_id_cmd),
fpi_ssm_usb_transfer_cb);
break;
@@ -630,7 +631,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
break;
case ACTIVATE_SEND_INIT_CMD:
fp_dbg ("Activate: send init seq #%d cmd #%d\n",
fp_dbg ("Activate: send init seq #%d cmd #%d",
priv->init_seq_idx,
priv->init_cmd_idx);
aesX660_send_cmd (ssm, _dev,
@@ -640,7 +641,7 @@ activate_run_state (FpiSsm *ssm, FpDevice *_dev)
break;
case ACTIVATE_READ_INIT_RESPONSE:
fp_dbg ("Activate: read init response\n");
fp_dbg ("Activate: read init response");
aesX660_read_response (ssm, _dev, TRUE, FALSE, INIT_LEN, activate_read_init_cb);
break;
+41 -131
View File
@@ -73,22 +73,19 @@ struct _FpiDeviceElan
/* end commands */
/* state */
gboolean deactivating;
FpiImageDeviceState dev_state;
FpiImageDeviceState dev_state_next;
unsigned char *last_read;
unsigned char calib_atts_left;
unsigned char calib_status;
unsigned short *background;
unsigned char frame_width;
unsigned char frame_height;
unsigned char raw_frame_height;
int num_frames;
GSList *frames;
gboolean active;
gboolean deactivating;
unsigned char *last_read;
unsigned char calib_atts_left;
unsigned char calib_status;
unsigned short *background;
unsigned char frame_width;
unsigned char frame_height;
unsigned char raw_frame_height;
int num_frames;
GSList *frames;
/* end state */
};
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
FpImageDevice);
G_DEFINE_TYPE (FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE);
static int
@@ -487,7 +484,7 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
/* The device is inactive at this point. */
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
self->active = FALSE;
if (self->deactivating)
{
@@ -505,16 +502,14 @@ stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
}
static void
elan_stop_capture (FpDevice *dev)
elan_stop_capture (FpiDeviceElan *self)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
G_DEBUG_HERE ();
elan_dev_reset_state (self);
FpiSsm *ssm =
fpi_ssm_new (dev, stop_capture_run_state, STOP_CAPTURE_NUM_STATES);
fpi_ssm_new (FP_DEVICE (self), stop_capture_run_state, STOP_CAPTURE_NUM_STATES);
fpi_ssm_start (ssm, stop_capture_complete);
}
@@ -545,8 +540,6 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev)
break;
case CAPTURE_READ_DATA:
self->dev_state = FPI_IMAGE_DEVICE_STATE_CAPTURE;
/* 0x55 - finger present
* 0xff - device not calibrated (probably) */
if (self->last_read && self->last_read[0] == 0x55)
@@ -614,18 +607,21 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
fpi_image_device_session_error (dev, error);
}
/* Note: We always stop capturing even if that may not be needed always.
* Doing this between captures appears to make it at least less likely for
* devices to end up in a bad state.
*/
elan_stop_capture (self);
}
static void
elan_capture (FpDevice *dev)
elan_capture (FpiDeviceElan *self)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
G_DEBUG_HERE ();
elan_dev_reset_state (self);
FpiSsm *ssm =
fpi_ssm_new (dev, capture_run_state, CAPTURE_NUM_STATES);
fpi_ssm_new (FP_DEVICE (self), capture_run_state, CAPTURE_NUM_STATES);
fpi_ssm_start (ssm, capture_complete);
}
@@ -777,33 +773,31 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
static void
calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
G_DEBUG_HERE ();
if (error)
{
self->dev_state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
elan_stop_capture (FPI_DEVICE_ELAN (dev));
}
else
{
elan_capture (dev);
elan_capture (FPI_DEVICE_ELAN (dev));
}
}
static void
elan_calibrate (FpDevice *dev)
elan_calibrate (FpiDeviceElan *self)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
G_DEBUG_HERE ();
elan_dev_reset_state (self);
g_return_if_fail (!self->active);
self->active = TRUE;
self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS;
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), calibrate_run_state,
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), calibrate_run_state,
CALIBRATE_NUM_STATES);
fpi_ssm_start (ssm, calibrate_complete);
@@ -958,98 +952,19 @@ dev_activate (FpImageDevice *dev)
elan_activate (dev);
}
static void
elan_change_state (FpImageDevice *idev)
{
FpDevice *dev = FP_DEVICE (idev);
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
FpiImageDeviceState next_state = self->dev_state_next;
if (self->dev_state == next_state)
{
fp_dbg ("already in %d", next_state);
return;
}
else
{
fp_dbg ("changing to %d", next_state);
}
switch (next_state)
{
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
/* activation completed or another enroll stage started */
self->dev_state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
elan_calibrate (dev);
break;
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
/* not used */
break;
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
elan_stop_capture (dev);
break;
}
}
static void
elan_change_state_async (FpDevice *dev,
void *data)
{
fp_dbg ("state change dev: %p", dev);
elan_change_state (FP_IMAGE_DEVICE (dev));
}
static void
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
GSource *timeout;
G_DEBUG_HERE ();
/* Inactive and await finger off are equivalent for the elan driver. */
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
if (self->dev_state_next == state)
{
fp_dbg ("change to state %d already queued", state);
return;
}
switch (state)
{
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: {
char *name;
/* schedule state change instead of calling it directly to allow all actions
* related to the previous state to complete */
self->dev_state_next = state;
timeout = fpi_device_add_timeout (FP_DEVICE (dev), 10,
elan_change_state_async,
NULL, NULL);
name = g_strdup_printf ("dev_change_state to %d", state);
g_source_set_name (timeout, name);
g_free (name);
break;
}
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
/* TODO MAYBE: split capture ssm into smaller ssms and use this state */
self->dev_state = state;
self->dev_state_next = state;
break;
default:
g_assert_not_reached ();
}
/* Note: We always calibrate even if that may not be needed always.
* Doing this for each capture appears to make it at least less likely for
* devices to end up in a bad state.
*/
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
elan_calibrate (self);
}
static void
@@ -1059,19 +974,14 @@ dev_deactivate (FpImageDevice *dev)
G_DEBUG_HERE ();
if (self->dev_state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
{
/* The device is inactive already, complete the operation immediately. */
fpi_image_device_deactivate_complete (dev, NULL);
}
if (!self->active)
/* The device is inactive already, complete the operation immediately. */
fpi_image_device_deactivate_complete (dev, NULL);
else
{
/* The device is not yet inactive, flag that we are deactivating (and
* need to signal back deactivation) and then ensure we will change
* to the inactive state eventually. */
self->deactivating = TRUE;
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
}
/* The device is not yet inactive, flag that we are deactivating (and
* need to signal back deactivation).
* Note that any running capture will be cancelled already if needed. */
self->deactivating = TRUE;
}
static void
+6 -2
View File
@@ -70,6 +70,9 @@
#define ELAN_CMD_TIMEOUT 10000
#define ELAN_FINGER_TIMEOUT 200
G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN,
FpImageDevice);
struct elan_cmd
{
unsigned char cmd[ELAN_CMD_LEN];
@@ -211,6 +214,7 @@ static const FpIdEntry elan_id_table[] = {
{.vid = ELAN_VEND_ID, .pid = 0x0c32, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c33, .driver_data = ELAN_ALL_DEV},
{.vid = ELAN_VEND_ID, .pid = 0x0c42, .driver_data = ELAN_0C42},
{.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV},
{.vid = 0, .pid = 0, .driver_data = 0},
};
@@ -218,8 +222,8 @@ static void elan_cmd_done (FpiSsm *ssm);
static void elan_cmd_read (FpiSsm *ssm,
FpDevice *dev);
static void elan_calibrate (FpDevice *dev);
static void elan_capture (FpDevice *dev);
static void elan_calibrate (FpiDeviceElan *self);
static void elan_capture (FpiDeviceElan *self);
static void dev_change_state (FpImageDevice *dev,
FpiImageDeviceState state);
+178 -4
View File
@@ -31,6 +31,10 @@ static const FpIdEntry id_table[] = {
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xBD, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xE9, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xDF, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xF9, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xFC, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xC2, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0xC9, },
{ .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
};
@@ -79,10 +83,17 @@ cmd_receive_cb (FpiUsbTransfer *transfer,
if (msg_resp.payload[0] == 0x01)
{
self->finger_on_sensor = TRUE;
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_PRESENT,
FP_FINGER_STATUS_NONE);
}
else
{
self->finger_on_sensor = FALSE;
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NONE,
FP_FINGER_STATUS_PRESENT);
if (self->cmd_complete_on_removal)
{
fpi_ssm_mark_completed (transfer->ssm);
@@ -194,12 +205,19 @@ cmd_interrupt_cb (FpiUsbTransfer *transfer,
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);
if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING)
{
fpi_ssm_next_state (transfer->ssm);
}
else
fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_interrupt_cb, NULL);
{
fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer),
0,
NULL,
cmd_interrupt_cb,
NULL);
}
}
static void
@@ -586,6 +604,9 @@ verify_msg_cb (FpiDeviceSynaptics *self,
switch (resp->response_id)
{
case BMKT_RSP_VERIFY_READY:
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
fp_info ("Place Finger on the Sensor!");
break;
@@ -659,6 +680,155 @@ verify (FpDevice *device)
synaptics_sensor_cmd (self, 0, BMKT_CMD_VERIFY_USER, user_id, user_id_len, verify_msg_cb);
}
static void
identify_complete_after_finger_removal (FpiDeviceSynaptics *self)
{
FpDevice *device = FP_DEVICE (self);
if (self->finger_on_sensor)
{
fp_dbg ("delaying identify report until after finger removal!");
self->cmd_complete_on_removal = TRUE;
}
else
{
fpi_device_identify_complete (device, NULL);
}
}
static void
identify_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
GError *error)
{
FpDevice *device = FP_DEVICE (self);
if (error)
{
fpi_device_identify_complete (device, error);
return;
}
if (resp == NULL && self->cmd_complete_on_removal)
{
fpi_device_identify_complete (device, NULL);
return;
}
g_assert (resp != NULL);
switch (resp->response_id)
{
case BMKT_RSP_ID_READY:
fp_info ("Place Finger on the Sensor!");
break;
case BMKT_RSP_ID_FAIL:
if (resp->result == BMKT_SENSOR_STIMULUS_ERROR)
{
fp_info ("Match error occurred");
fpi_device_identify_report (device, NULL, NULL,
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
identify_complete_after_finger_removal (self);
}
else if (resp->result == BMKT_FP_NO_MATCH)
{
fp_info ("Print didn't match");
fpi_device_identify_report (device, NULL, NULL, NULL);
identify_complete_after_finger_removal (self);
}
else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
{
fp_info ("Print is not in database");
fpi_device_identify_complete (device,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
}
else
{
fp_warn ("identify has failed: %d", resp->result);
fpi_device_identify_complete (device,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected result from device %d",
resp->result));
}
break;
case BMKT_RSP_ID_OK:
{
FpPrint *print = NULL;
GPtrArray *prints = NULL;
g_autoptr(GVariant) data = NULL;
guint8 finger;
const guint8 *user_id;
gsize user_id_len = 0;
gint cnt = 0;
gboolean find = FALSE;
fpi_device_get_identify_data (device, &prints);
for (cnt = 0; cnt < prints->len; cnt++)
{
print = g_ptr_array_index (prints, cnt);
g_object_get (print, "fpi-data", &data, NULL);
g_debug ("data is %p", data);
parse_print_data (data, &finger, &user_id, &user_id_len);
if (user_id)
{
if (memcmp (resp->response.id_resp.user_id, user_id, user_id_len) == 0)
{
find = TRUE;
break;
}
}
}
if(find)
{
fpi_device_identify_report (device, print, print, NULL);
fpi_device_identify_complete (device, NULL);
}
else
{
fpi_device_identify_report (device, NULL, NULL, NULL);
identify_complete_after_finger_removal (self);
}
}
}
}
static void
identify (FpDevice *device)
{
FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
FpPrint *print = NULL;
GPtrArray *prints = NULL;
g_autoptr(GVariant) data = NULL;
guint8 finger;
const guint8 *user_id;
gsize user_id_len = 0;
gint cnt = 0;
fpi_device_get_identify_data (device, &prints);
for (cnt = 0; cnt < prints->len; cnt++)
{
print = g_ptr_array_index (prints, cnt);
g_object_get (print, "fpi-data", &data, NULL);
g_debug ("data is %p", data);
if (!parse_print_data (data, &finger, &user_id, &user_id_len))
{
fpi_device_identify_complete (device,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
return;
}
}
G_DEBUG_HERE ();
synaptics_sensor_cmd (self, 0, BMKT_CMD_ID_USER, NULL, 0, identify_msg_cb);
}
static void
enroll_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
@@ -680,6 +850,9 @@ enroll_msg_cb (FpiDeviceSynaptics *self,
case BMKT_RSP_ENROLL_READY:
{
self->enroll_stage = 0;
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
fp_info ("Place Finger on the Sensor!");
break;
}
@@ -1152,6 +1325,7 @@ fpi_device_synaptics_class_init (FpiDeviceSynapticsClass *klass)
dev_class->close = dev_exit;
dev_class->probe = dev_probe;
dev_class->verify = verify;
dev_class->identify = identify;
dev_class->enroll = enroll;
dev_class->delete = delete_print;
dev_class->cancel = cancel;
+4 -4
View File
@@ -171,7 +171,7 @@ finger_present (unsigned char *img, size_t len, int sum_threshold)
if (img[i] < 160)
sum++;
fp_dbg ("finger_present: sum is %d\n", sum);
fp_dbg ("finger_present: sum is %d", sum);
return sum < sum_threshold ? 0 : 1;
}
@@ -184,7 +184,7 @@ finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (error)
{
fp_dbg ("data transfer status %s\n", error->message);
fp_dbg ("data transfer status %s", error->message);
fpi_image_device_session_error (dev, error);
return;
}
@@ -212,7 +212,7 @@ finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device,
if (error)
{
fp_dbg ("req transfer status %s\n", error->message);
fp_dbg ("req transfer status %s", error->message);
fpi_image_device_session_error (dev, error);
return;
}
@@ -411,7 +411,7 @@ dev_init (FpImageDevice *dev)
break;
default:
fp_err ("Device variant %lu is not known\n", driver_data);
fp_err ("Device variant %lu is not known", driver_data);
g_assert_not_reached ();
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
return;
+11 -10
View File
@@ -78,6 +78,7 @@ upektc_img_cmd_update_crc (unsigned char *cmd_buf, size_t size)
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
}
FP_GNUC_ACCESS (read_only, 3, 4)
static void
upektc_img_submit_req (FpiSsm *ssm,
FpImageDevice *dev,
@@ -193,7 +194,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (self->deactivating)
{
fp_dbg ("Deactivate requested\n");
fp_dbg ("Deactivate requested");
fpi_ssm_mark_completed (transfer->ssm);
return;
}
@@ -208,7 +209,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
if (fpi_ssm_get_cur_state (transfer->ssm) == CAPTURE_READ_DATA_TERM)
{
fp_dbg ("Terminating SSM\n");
fp_dbg ("Terminating SSM");
fpi_ssm_mark_completed (transfer->ssm);
return;
}
@@ -219,7 +220,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
response_size += 9; /* 7 bytes for header, 2 for CRC */
if (response_size > transfer->actual_length)
{
fp_dbg ("response_size is %lu, actual_length is %d\n",
fp_dbg ("response_size is %lu, actual_length is %d",
response_size, (gint) transfer->actual_length);
fp_dbg ("Waiting for rest of transfer");
BUG_ON (self->response_rest);
@@ -237,7 +238,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
{
/* No finger */
case 0x28:
fp_dbg ("18th byte is %.2x\n", data[18]);
fp_dbg ("18th byte is %.2x", data[18]);
switch (data[18])
{
case 0x0c:
@@ -254,7 +255,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
case 0x1e:
/* short scan */
fp_err ("short scan, aborting\n");
fp_err ("short scan, aborting");
fpi_image_device_retry_scan (dev,
FP_DEVICE_RETRY_TOO_SHORT);
fpi_image_device_report_finger_status (dev,
@@ -265,7 +266,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
case 0x1d:
/* too much horisontal movement */
fp_err ("too much horisontal movement, aborting\n");
fp_err ("too much horisontal movement, aborting");
fpi_image_device_retry_scan (dev,
FP_DEVICE_RETRY_CENTER_FINGER);
fpi_image_device_report_finger_status (dev,
@@ -276,7 +277,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
default:
/* some error happened, cancel scan */
fp_err ("something bad happened, stop scan\n");
fp_err ("something bad happened, stop scan");
fpi_image_device_retry_scan (dev,
FP_DEVICE_RETRY);
fpi_image_device_report_finger_status (dev,
@@ -307,7 +308,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
upektc_img_process_image_frame (self->image_bits + self->image_size,
data);
BUG_ON (self->image_size != IMAGE_SIZE);
fp_dbg ("Image size is %lu\n",
fp_dbg ("Image size is %lu",
self->image_size);
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
img->flags |= FPI_IMAGE_PARTIAL;
@@ -320,7 +321,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
break;
default:
fp_err ("Unknown response!\n");
fp_err ("Unknown response!");
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
break;
}
@@ -331,7 +332,7 @@ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
break;
default:
fp_err ("Not handled response!\n");
fp_err ("Not handled response!");
fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
}
}
-9
View File
@@ -527,15 +527,6 @@ initsm_read_msg_response_cb (FpiSsm *ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected response subcommand"));
}
else if (seq != upekdev->seq)
{
fp_err ("expected response to cmd seq=%02x, got response to %02x "
"in state %d", upekdev->seq, seq,
fpi_ssm_get_cur_state (ssm));
fpi_ssm_mark_failed (ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected sequence number in response"));
}
else
{
fpi_ssm_next_state (ssm);
+18 -18
View File
@@ -412,18 +412,6 @@ dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiDeviceUru4000 *self = FPI_DEVICE_URU4000 (dev);
switch (state)
{
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON:
case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF:
case FPI_IMAGE_DEVICE_STATE_CAPTURE:
break;
default:
g_assert_not_reached ();
}
self->activate_state = state;
if (self->img_transfer != NULL)
return;
@@ -663,7 +651,11 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
case IMAGING_CAPTURE:
self->img_lines_done = 0;
self->img_block = 0;
fpi_usb_transfer_submit (self->img_transfer, 0, NULL, image_transfer_cb, NULL);
fpi_usb_transfer_submit (fpi_usb_transfer_ref (self->img_transfer),
0,
NULL,
image_transfer_cb,
NULL);
break;
@@ -723,7 +715,7 @@ imaging_run_state (FpiSsm *ssm, FpDevice *_dev)
num_lines);
if (flags & BLOCKF_CHANGE_KEY)
{
fp_dbg ("changing encryption keys.\n");
fp_dbg ("changing encryption keys.");
img->block_info[self->img_block].flags &= ~BLOCKF_CHANGE_KEY;
img->key_number++;
self->img_enc_seed = rand ();
@@ -799,8 +791,7 @@ imaging_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error)
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
/* Freed by callback or cancellation */
self->img_transfer = NULL;
g_clear_pointer (&self->img_transfer, fpi_usb_transfer_unref);
g_free (self->img_data);
self->img_data = NULL;
@@ -1182,7 +1173,10 @@ deactivate_write_reg_cb (FpiUsbTransfer *transfer, FpDevice *dev,
static void
dev_deactivate (FpImageDevice *dev)
{
dev_change_state (dev, FPI_IMAGE_DEVICE_STATE_INACTIVE);
/* This is started/handled by execute_state_change in order to delay the
* action until after the image transfer has completed.
* We just need to override the function so that the complete handler is
* not called automatically. */
}
static void
@@ -1193,7 +1187,7 @@ execute_state_change (FpImageDevice *dev)
switch (self->activate_state)
{
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
case FPI_IMAGE_DEVICE_STATE_DEACTIVATING:
fp_dbg ("deactivating");
self->irq_cb = NULL;
self->irq_cb_data = NULL;
@@ -1248,6 +1242,12 @@ execute_state_change (FpImageDevice *dev)
write_reg (dev, REG_MODE, MODE_AWAIT_FINGER_OFF,
change_state_write_reg_cb, NULL);
break;
/* Ignored states */
case FPI_IMAGE_DEVICE_STATE_IDLE:
case FPI_IMAGE_DEVICE_STATE_ACTIVATING:
case FPI_IMAGE_DEVICE_STATE_INACTIVE:
break;
}
}
+1
View File
@@ -42,6 +42,7 @@ async_write_callback (FpiUsbTransfer *transfer, FpDevice *device,
}
/* Send data to EP1, the only out endpoint */
FP_GNUC_ACCESS (read_only, 3, 4)
static void
async_write (FpiSsm *ssm,
FpDevice *dev,
+14 -24
View File
@@ -147,18 +147,6 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
}
}
/* Complete loop sequential state machine */
static void
m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
{
if (error)
{
g_warning ("State machine completed with an error: %s", error->message);
g_error_free (error);
}
/* Free sequential state machine */
}
/* Exec init sequential state machine */
static void
m_init_state (FpiSsm *ssm, FpDevice *_dev)
@@ -176,19 +164,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
static void
m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
{
FpiSsm *ssm_loop;
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
if (!error)
{
/* Notify activate complete */
/* Start loop ssm */
ssm_loop = fpi_ssm_new (dev, m_loop_state, M_LOOP_NUM_STATES);
fpi_ssm_start (ssm_loop, m_loop_complete);
}
/* Free sequential state machine */
}
/* Activate device */
@@ -213,6 +189,19 @@ dev_deactivate (FpImageDevice *dev)
fpi_image_device_deactivate_complete (dev, NULL);
}
static void
dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
{
FpiSsm *ssm_loop;
if (state != FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
return;
/* Start a capture operation. */
ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES);
fpi_ssm_start (ssm_loop, NULL);
}
static void
dev_open (FpImageDevice *dev)
{
@@ -273,6 +262,7 @@ fpi_device_vfs301_class_init (FpDeviceVfs301Class *klass)
img_class->img_close = dev_close;
img_class->activate = dev_activate;
img_class->deactivate = dev_deactivate;
img_class->change_state = dev_change_state;
img_class->bz3_threshold = 24;
+6 -12
View File
@@ -93,6 +93,7 @@ usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **
*out = g_steal_pointer (&transfer);
}
FP_GNUC_ACCESS (read_only, 2, 3)
static void
usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error)
{
@@ -212,11 +213,9 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
*len = 1;
return data;
}
break;
case 0x0B:
return vfs301_proto_generate_0B (subtype, len);
break;
case 0x02D0:
{
@@ -232,22 +231,18 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
g_assert ((int) subtype <= G_N_ELEMENTS (dataLs));
return translate_str (dataLs[subtype - 1], len);
}
break;
case 0x0220:
switch (subtype)
{
case 1:
return translate_str (vfs301_0220_01, len);
break;
case 2:
return translate_str (vfs301_0220_02, len);
break;
case 3:
return translate_str (vfs301_0220_03, len);
break;
case 0xFA00:
case 0x2C01:
@@ -270,7 +265,6 @@ vfs301_proto_generate (int type, int subtype, gssize *len)
field[3] = field[1];
return data;
break;
}
default:
@@ -508,30 +502,30 @@ vfs301_proto_process_event_cb (FpiUsbTransfer *transfer,
FpDevice *device,
gpointer user_data, GError *error)
{
FpDeviceVfs301 *dev = user_data;
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (device);
if (error)
{
g_warning ("Error receiving data: %s", error->message);
g_error_free (error);
dev->recv_progress = VFS301_FAILURE;
self->recv_progress = VFS301_FAILURE;
return;
}
else if (transfer->actual_length < transfer->length)
{
/* TODO: process the data anyway? */
dev->recv_progress = VFS301_ENDED;
self->recv_progress = VFS301_ENDED;
return;
}
else
{
FpiUsbTransfer *new;
if (!vfs301_proto_process_data (dev,
if (!vfs301_proto_process_data (self,
transfer->length == VFS301_FP_RECV_LEN_1,
transfer->buffer,
transfer->actual_length))
{
dev->recv_progress = VFS301_ENDED;
self->recv_progress = VFS301_ENDED;
return;
}
+120 -24
View File
@@ -42,6 +42,7 @@ struct _FpDeviceVirtualImage
GSocketListener *listener;
GSocketConnection *connection;
GCancellable *listen_cancellable;
GCancellable *cancellable;
gint socket_fd;
@@ -72,14 +73,21 @@ recv_image_img_recv_cb (GObject *source_object,
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
if (!success || bytes == 0)
/* Can't use self if the operation was cancelled. */
if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
device = FP_IMAGE_DEVICE (self);
/* Consider success if we received the right amount of data, otherwise
* an error must have happened. */
if (bytes < self->recv_img->width * self->recv_img->height)
{
if (!success)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Error receiving header for image data: %s", error->message);
}
g_warning ("Error receiving image data: %s", error->message);
else
g_warning ("Error receiving image data: end of stream before all data was read");
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
@@ -87,9 +95,6 @@ recv_image_img_recv_cb (GObject *source_object,
return;
}
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
device = FP_IMAGE_DEVICE (self);
if (self->automatic_finger)
fpi_image_device_report_finger_status (device, TRUE);
fpi_image_device_image_captured (device, g_steal_pointer (&self->recv_img));
@@ -112,7 +117,7 @@ recv_image_hdr_recv_cb (GObject *source_object,
success = g_input_stream_read_all_finish (G_INPUT_STREAM (source_object), res, &bytes, &error);
if (!success || bytes == 0)
if (!success || bytes != sizeof (self->recv_img_hdr))
{
if (!success)
{
@@ -121,6 +126,10 @@ recv_image_hdr_recv_cb (GObject *source_object,
return;
g_warning ("Error receiving header for image data: %s", error->message);
}
else if (bytes != 0)
{
g_warning ("Received incomplete header before end of stream.");
}
self = FPI_DEVICE_VIRTUAL_IMAGE (user_data);
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
@@ -162,6 +171,11 @@ recv_image_hdr_recv_cb (GObject *source_object,
!!self->recv_img_hdr[1]);
break;
case -5:
/* -5 causes the device to disappear (no further data) */
fpi_device_remove (FP_DEVICE (self));
break;
default:
/* disconnect client, it didn't play fair */
g_io_stream_close (G_IO_STREAM (self->connection), NULL, NULL);
@@ -185,15 +199,25 @@ recv_image_hdr_recv_cb (GObject *source_object,
}
static void
recv_image (FpDeviceVirtualImage *dev, GInputStream *stream)
recv_image (FpDeviceVirtualImage *self, GInputStream *stream)
{
g_input_stream_read_all_async (stream,
dev->recv_img_hdr,
sizeof (dev->recv_img_hdr),
G_PRIORITY_DEFAULT,
dev->cancellable,
recv_image_hdr_recv_cb,
dev);
FpiImageDeviceState state;
g_object_get (self, "fpi-image-device-state", &state, NULL);
g_debug ("Starting image receive (if active), state is: %i", state);
/* Only register if the state is active. */
if (state >= FPI_IMAGE_DEVICE_STATE_IDLE)
{
g_input_stream_read_all_async (stream,
self->recv_img_hdr,
sizeof (self->recv_img_hdr),
G_PRIORITY_DEFAULT,
self->cancellable,
recv_image_hdr_recv_cb,
self);
}
}
static void
@@ -217,11 +241,25 @@ new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
start_listen (dev);
}
/* Always further connections (but we disconnect them immediately
/* Always accept further connections (but we disconnect them immediately
* if we already have a connection). */
start_listen (dev);
if (dev->connection)
{
/* We may not have noticed that the stream was closed,
* if the device is deactivated.
* Cancel any ongoing operation on the old connection. */
g_cancellable_cancel (dev->cancellable);
g_clear_object (&dev->cancellable);
dev->cancellable = g_cancellable_new ();
g_clear_object (&dev->connection);
}
if (dev->connection)
{
g_warning ("Rejecting new connection");
g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
g_object_unref (connection);
return;
@@ -231,16 +269,15 @@ new_connection_cb (GObject *source_object, GAsyncResult *res, gpointer user_data
dev->automatic_finger = TRUE;
stream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
recv_image (dev, stream);
fp_dbg ("Got a new connection!");
recv_image (dev, stream);
}
static void
start_listen (FpDeviceVirtualImage *dev)
{
g_socket_listener_accept_async (dev->listener,
dev->cancellable,
dev->listen_cancellable,
new_connection_cb,
dev);
}
@@ -285,10 +322,12 @@ dev_init (FpImageDevice *dev)
self->listener = g_steal_pointer (&listener);
self->cancellable = g_cancellable_new ();
self->listen_cancellable = g_cancellable_new ();
start_listen (self);
fpi_image_device_open_complete (dev, NULL);
/* Delay result to open up the possibility of testing race conditions. */
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_open_complete, NULL, NULL);
}
static void
@@ -299,16 +338,70 @@ dev_deinit (FpImageDevice *dev)
G_DEBUG_HERE ();
g_cancellable_cancel (self->cancellable);
g_cancellable_cancel (self->listen_cancellable);
g_clear_object (&self->cancellable);
g_clear_object (&self->listen_cancellable);
g_clear_object (&self->listener);
g_clear_object (&self->connection);
fpi_image_device_close_complete (dev, NULL);
/* Delay result to open up the possibility of testing race conditions. */
fpi_device_add_timeout (FP_DEVICE (dev), 100, (FpTimeoutFunc) fpi_image_device_close_complete, NULL, NULL);
}
static void
dev_activate (FpImageDevice *dev)
{
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
fpi_image_device_activate_complete (dev, NULL);
if (self->connection)
recv_image (self, g_io_stream_get_input_stream (G_IO_STREAM (self->connection)));
}
static void
dev_deactivate (FpImageDevice *dev)
{
FpDeviceVirtualImage *self = FPI_DEVICE_VIRTUAL_IMAGE (dev);
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
self->cancellable = g_cancellable_new ();
/* XXX: Need to wait for the operation to be cancelled. */
fpi_device_add_timeout (FP_DEVICE (dev), 10, (FpTimeoutFunc) fpi_image_device_deactivate_complete, NULL, NULL);
}
static void
dev_notify_removed_cb (FpDevice *dev)
{
FpiImageDeviceState state;
gboolean removed;
g_object_get (dev,
"fpi-image-device-state", &state,
"removed", &removed,
NULL);
if (!removed || state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
return;
/* This error will be converted to an FP_DEVICE_ERROR_REMOVED by the
* surrounding layers. */
fpi_image_device_session_error (FP_IMAGE_DEVICE (dev),
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
}
static void
fpi_device_virtual_image_init (FpDeviceVirtualImage *self)
{
/* NOTE: This is not nice, but we can generally rely on the underlying
* system to throw errors on the transport layer.
*/
g_signal_connect (self,
"notify::removed",
G_CALLBACK (dev_notify_removed_cb),
NULL);
}
static const FpIdEntry driver_ids[] = {
@@ -329,4 +422,7 @@ fpi_device_virtual_image_class_init (FpDeviceVirtualImageClass *klass)
img_class->img_open = dev_init;
img_class->img_close = dev_deinit;
img_class->activate = dev_activate;
img_class->deactivate = dev_deactivate;
}
+62 -6
View File
@@ -91,6 +91,60 @@ is_driver_allowed (const gchar *driver)
return FALSE;
}
typedef struct
{
FpContext *context;
FpDevice *device;
} RemoveDeviceData;
static gboolean
remove_device_idle_cb (RemoveDeviceData *data)
{
FpContextPrivate *priv = fp_context_get_instance_private (data->context);
guint idx = 0;
g_return_val_if_fail (g_ptr_array_find (priv->devices, data->device, &idx), G_SOURCE_REMOVE);
g_signal_emit (data->context, signals[DEVICE_REMOVED_SIGNAL], 0, data->device);
g_ptr_array_remove_index_fast (priv->devices, idx);
g_free (data);
return G_SOURCE_REMOVE;
}
static void
remove_device (FpContext *context, FpDevice *device)
{
RemoveDeviceData *data;
data = g_new (RemoveDeviceData, 1);
data->context = context;
data->device = device;
g_idle_add ((GSourceFunc) remove_device_idle_cb, data);
}
static void
device_remove_on_notify_open_cb (FpContext *context, GParamSpec *pspec, FpDevice *device)
{
remove_device (context, device);
}
static void
device_removed_cb (FpContext *context, FpDevice *device)
{
gboolean open = FALSE;
g_object_get (device, "open", &open, NULL);
/* Wait for device close if the device is currently still open. */
if (open)
g_signal_connect_swapped (device, "notify::open", (GCallback) device_remove_on_notify_open_cb, context);
else
remove_device (context, device);
}
static void
async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
@@ -115,6 +169,9 @@ async_device_init_done_cb (GObject *source_object, GAsyncResult *res, gpointer u
}
g_ptr_array_add (priv->devices, device);
g_signal_connect_swapped (device, "removed", (GCallback) device_removed_cb, context);
g_signal_emit (context, signals[DEVICE_ADDED_SIGNAL], 0, device);
}
@@ -194,12 +251,7 @@ usb_device_removed_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx
continue;
if (fpi_device_get_usb_device (dev) == device)
{
g_signal_emit (self, signals[DEVICE_REMOVED_SIGNAL], 0, dev);
g_ptr_array_remove_index_fast (priv->devices, i);
return;
}
fpi_device_remove (dev);
}
}
@@ -255,6 +307,10 @@ fp_context_class_init (FpContextClass *klass)
* @device: A #FpDevice
*
* This signal is emitted when a fingerprint reader is removed.
*
* It is guaranteed that the device has been closed before this signal
* is emitted. See the #FpDevice removed signal documentation for more
* information.
**/
signals[DEVICE_REMOVED_SIGNAL] = g_signal_new ("device-removed",
G_TYPE_FROM_CLASS (klass),
+3 -1
View File
@@ -29,6 +29,7 @@ typedef struct
GUsbDevice *usb_device;
const gchar *virtual_env;
gboolean is_removed;
gboolean is_open;
gchar *device_id;
@@ -49,7 +50,8 @@ typedef struct
GSource *current_task_idle_return_source;
/* State for tasks */
gboolean wait_for_finger;
gboolean wait_for_finger;
FpFingerStatusFlags finger_status;
} FpDevicePrivate;
+82
View File
@@ -44,8 +44,10 @@ enum {
PROP_DEVICE_ID,
PROP_NAME,
PROP_OPEN,
PROP_REMOVED,
PROP_NR_ENROLL_STAGES,
PROP_SCAN_TYPE,
PROP_FINGER_STATUS,
PROP_FPI_ENVIRON,
PROP_FPI_USB_DEVICE,
PROP_FPI_DRIVER_DATA,
@@ -54,6 +56,13 @@ enum {
static GParamSpec *properties[N_PROPS];
enum {
REMOVED_SIGNAL,
N_SIGNALS
};
static guint signals[N_SIGNALS] = { 0, };
/**
* fp_device_retry_quark:
*
@@ -84,6 +93,8 @@ fp_device_cancel_in_idle_cb (gpointer user_data)
cls->cancel (self);
fpi_device_report_finger_status (self, FP_FINGER_STATUS_NONE);
return G_SOURCE_REMOVE;
}
@@ -181,6 +192,10 @@ fp_device_get_property (GObject *object,
g_value_set_enum (value, priv->scan_type);
break;
case PROP_FINGER_STATUS:
g_value_set_enum (value, priv->finger_status);
break;
case PROP_DRIVER:
g_value_set_static_string (value, FP_DEVICE_GET_CLASS (priv)->id);
break;
@@ -197,6 +212,10 @@ fp_device_get_property (GObject *object,
g_value_set_boolean (value, priv->is_open);
break;
case PROP_REMOVED:
g_value_set_boolean (value, priv->is_removed);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -310,6 +329,13 @@ fp_device_class_init (FpDeviceClass *klass)
FP_TYPE_SCAN_TYPE, FP_SCAN_TYPE_SWIPE,
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
properties[PROP_FINGER_STATUS] =
g_param_spec_flags ("finger-status",
"FingerStatus",
"The status of the finger",
FP_TYPE_FINGER_STATUS_FLAGS, FP_FINGER_STATUS_NONE,
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
properties[PROP_DRIVER] =
g_param_spec_string ("driver",
"Driver",
@@ -337,6 +363,41 @@ fp_device_class_init (FpDeviceClass *klass)
"Whether the device is open or not", FALSE,
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
properties[PROP_REMOVED] =
g_param_spec_boolean ("removed",
"Removed",
"Whether the device has been removed from the system", FALSE,
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
/**
* FpDevice::removed:
* @device: the #FpDevice instance that emitted the signal
*
* This signal is emitted after the device has been removed and no operation
* is pending anymore.
*
* The API user is still required to close a removed device. The above
* guarantee means that the call to close the device can be made immediately
* from the signal handler.
*
* The close operation will return FP_DEVICE_ERROR_REMOVED, but the device
* will still be considered closed afterwards.
*
* The device will only be removed from the #FpContext after it has been
* closed by the API user.
**/
signals[REMOVED_SIGNAL] = g_signal_new ("removed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
/* Private properties */
/**
* FpDevice::fpi-environ: (skip)
*
@@ -469,6 +530,26 @@ fp_device_get_scan_type (FpDevice *device)
return priv->scan_type;
}
/**
* fp_device_get_finger_status:
* @device: A #FpDevice
*
* Retrieves the finger status flags for the device.
* This can be used by the UI to present the relevant feedback, although it
* is not guaranteed to be a relevant value when not performing any action.
*
* Returns: The current #FpFingerStatusFlags
*/
FpFingerStatusFlags
fp_device_get_finger_status (FpDevice *device)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
g_return_val_if_fail (FP_IS_DEVICE (device), FP_SCAN_TYPE_SWIPE);
return priv->finger_status;
}
/**
* fp_device_get_nr_enroll_stages:
* @device: A #FpDevice
@@ -603,6 +684,7 @@ fp_device_open (FpDevice *device,
priv->current_action = FPI_DEVICE_ACTION_OPEN;
priv->current_task = g_steal_pointer (&task);
maybe_cancel_on_cancelled (device, cancellable);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
FP_DEVICE_GET_CLASS (device)->open (device);
}
+4
View File
@@ -91,6 +91,7 @@ typedef enum {
* @FP_DEVICE_ERROR_DATA_NOT_FOUND: Requested print was not found on device
* @FP_DEVICE_ERROR_DATA_FULL: No space on device available for operation
* @FP_DEVICE_ERROR_DATA_DUPLICATE: Enrolling template duplicates storaged templates
* @FP_DEVICE_ERROR_REMOVED: The device has been removed.
*
* Error codes for device operations. More specific errors from other domains
* such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
@@ -106,6 +107,8 @@ typedef enum {
FP_DEVICE_ERROR_DATA_NOT_FOUND,
FP_DEVICE_ERROR_DATA_FULL,
FP_DEVICE_ERROR_DATA_DUPLICATE,
/* Leave some room to add more DATA related errors */
FP_DEVICE_ERROR_REMOVED = 0x100,
} FpDeviceError;
GQuark fp_device_retry_quark (void);
@@ -170,6 +173,7 @@ const gchar *fp_device_get_device_id (FpDevice *device);
const gchar *fp_device_get_name (FpDevice *device);
gboolean fp_device_is_open (FpDevice *device);
FpScanType fp_device_get_scan_type (FpDevice *device);
FpFingerStatusFlags fp_device_get_finger_status (FpDevice *device);
gint fp_device_get_nr_enroll_stages (FpDevice *device);
gboolean fp_device_supports_identify (FpDevice *device);
+7 -5
View File
@@ -27,17 +27,19 @@ typedef struct
{
FpiImageDeviceState state;
gboolean active;
gboolean cancelling;
gboolean enroll_await_on_pending;
gboolean finger_present;
gint enroll_stage;
guint pending_activation_timeout_id;
gboolean pending_activation_timeout_waiting_finger_off;
gboolean minutiae_scan_active;
GError *action_error;
FpImage *capture_image;
gint bz3_threshold;
} FpImageDevicePrivate;
void fpi_image_device_activate (FpImageDevice *image_device);
void fpi_image_device_deactivate (FpImageDevice *image_device);
void fpi_image_device_deactivate (FpImageDevice *image_device,
gboolean cancelling);
+6 -85
View File
@@ -56,44 +56,6 @@ static guint signals[LAST_SIGNAL] = { 0 };
* - sanitize_image seems a bit odd, in particular the sizing stuff.
**/
/* Static helper functions */
static gboolean
pending_activation_timeout (gpointer user_data)
{
FpImageDevice *self = FP_IMAGE_DEVICE (user_data);
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action = fpi_device_get_current_action (device);
GError *error;
priv->pending_activation_timeout_id = 0;
if (priv->pending_activation_timeout_waiting_finger_off)
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
"Remove finger before requesting another scan operation");
else
error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
if (action == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL, error);
fpi_device_verify_complete (device, NULL);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_identify_report (device, NULL, NULL, error);
fpi_device_identify_complete (device, NULL);
}
else
{
/* Can this happen for enroll? */
fpi_device_action_error (device, error);
}
return G_SOURCE_REMOVE;
}
/* Callbacks/vfuncs */
static void
fp_image_device_open (FpDevice *device)
@@ -112,26 +74,14 @@ fp_image_device_close (FpDevice *device)
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
/* In the close case we may need to wait/force deactivation first.
* Three possible cases:
* 1. We are inactive
* -> immediately close
* 2. We are waiting for finger off
* -> immediately deactivate
* 3. We are deactivating
* -> handled by deactivate_complete */
if (!priv->active)
cls->img_close (self);
else if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE)
fpi_image_device_deactivate (self);
g_assert (priv->active == FALSE);
cls->img_close (self);
}
static void
fp_image_device_cancel_action (FpDevice *device)
{
FpImageDevice *self = FP_IMAGE_DEVICE (device);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
action = fpi_device_get_current_action (device);
@@ -142,17 +92,7 @@ fp_image_device_cancel_action (FpDevice *device)
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE)
{
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
/* XXX: Some nicer way of doing this would be good. */
fpi_device_action_error (FP_DEVICE (self),
g_error_new (G_IO_ERROR,
G_IO_ERROR_CANCELLED,
"Device operation was cancelled"));
}
fpi_image_device_deactivate (self, TRUE);
}
static void
@@ -188,27 +128,9 @@ fp_image_device_start_capture_action (FpDevice *device)
}
priv->enroll_stage = 0;
priv->enroll_await_on_pending = FALSE;
/* The device might still be deactivating from a previous call.
* In that situation, try to wait for a bit before reporting back an
* error (which will usually say that the user should remove the
* finger).
*/
if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE || priv->active)
{
g_debug ("Got a new request while the device was still active");
g_assert (priv->pending_activation_timeout_id == 0);
priv->pending_activation_timeout_id =
g_timeout_add (100, pending_activation_timeout, device);
if (priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
priv->pending_activation_timeout_waiting_finger_off = TRUE;
else
priv->pending_activation_timeout_waiting_finger_off = FALSE;
return;
}
/* The internal state machine guarantees both of these. */
g_assert (!priv->finger_present);
g_assert (!priv->minutiae_scan_active);
/* And activate the device; we rely on fpi_image_device_activate_complete()
* to be called when done (or immediately). */
@@ -225,7 +147,6 @@ fp_image_device_finalize (GObject *object)
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_assert (priv->active == FALSE);
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
G_OBJECT_CLASS (fp_image_device_parent_class)->finalize (object);
}
+12
View File
@@ -66,6 +66,18 @@ typedef enum {
FP_FINGER_LAST = FP_FINGER_RIGHT_LITTLE,
} FpFinger;
/**
* FpFingerStatusFlags:
* @FP_FINGER_STATUS_NONE: Sensor has not the finger on it, nor requires it
* @FP_FINGER_STATUS_NEEDED: Sensor waits for the finger
* @FP_FINGER_STATUS_PRESENT: Sensor has the finger on it
*/
typedef enum {
FP_FINGER_STATUS_NONE = 0,
FP_FINGER_STATUS_NEEDED = 1 << 0,
FP_FINGER_STATUS_PRESENT = 1 << 1,
} FpFingerStatusFlags;
FpPrint *fp_print_new (FpDevice *device);
FpPrint *fp_print_new_from_data (guchar *data,
+6
View File
@@ -37,3 +37,9 @@ typedef struct _FpDeviceClass FpDeviceClass;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpDeviceClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free);
#endif
#if __GNUC__ > 10 || (__GNUC__ == 10 && __GNUC_MINOR__ >= 1)
#define FP_GNUC_ACCESS(m, p, s) __attribute__((access (m, p, s)))
#else
#define FP_GNUC_ACCESS(m, p, s)
#endif
+169 -12
View File
@@ -139,6 +139,10 @@ fpi_device_error_new (FpDeviceError error)
msg = "This finger has already enrolled, please try a different finger";
break;
case FP_DEVICE_ERROR_REMOVED:
msg = "This device has been removed from the system.";
break;
default:
g_warning ("Unsupported error, returning general error instead!");
error = FP_DEVICE_ERROR_GENERAL;
@@ -576,6 +580,49 @@ fpi_device_get_cancellable (FpDevice *device)
return g_task_get_cancellable (priv->current_task);
}
static void
emit_removed_on_task_completed (FpDevice *device)
{
g_signal_emit_by_name (device, "removed");
}
/**
* fpi_device_remove:
* @device: The #FpDevice
*
* Called to signal to the #FpDevice that it has been unplugged (physically
* removed from the system).
*
* For USB devices, this API is called automatically by #FpContext.
*/
void
fpi_device_remove (FpDevice *device)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (!priv->is_removed);
priv->is_removed = TRUE;
g_object_notify (G_OBJECT (device), "removed");
/* If there is a pending action, we wait for it to fail, otherwise we
* immediately emit the "removed" signal. */
if (priv->current_task)
{
g_signal_connect_object (priv->current_task,
"notify::completed",
(GCallback) emit_removed_on_task_completed,
device,
G_CONNECT_SWAPPED);
}
else
{
g_signal_emit_by_name (device, "removed");
}
}
/**
* fpi_device_action_error:
* @device: The #FpDevice
@@ -691,6 +738,7 @@ fp_device_task_return_in_idle_cb (gpointer user_data)
FpDeviceTaskReturnData *data = user_data;
FpDevicePrivate *priv = fp_device_get_instance_private (data->device);
g_autofree char *action_str = NULL;
FpiDeviceAction action;
g_autoptr(GTask) task = NULL;
@@ -699,9 +747,24 @@ fp_device_task_return_in_idle_cb (gpointer user_data)
g_debug ("Completing action %s in idle!", action_str);
task = g_steal_pointer (&priv->current_task);
action = priv->current_action;
priv->current_action = FPI_DEVICE_ACTION_NONE;
priv->current_task_idle_return_source = NULL;
/* Return FP_DEVICE_ERROR_REMOVED if the device is removed,
* with the exception of a successful open, which is an odd corner case. */
if (priv->is_removed &&
((action != FPI_DEVICE_ACTION_OPEN) ||
(action == FPI_DEVICE_ACTION_OPEN && data->type == FP_DEVICE_TASK_RETURN_ERROR)))
{
g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_REMOVED));
/* NOTE: The removed signal will be emitted from the GTask
* notify::completed if that is neccessary. */
return G_SOURCE_REMOVE;
}
switch (data->type)
{
case FP_DEVICE_TASK_RETURN_INT:
@@ -713,16 +776,17 @@ fp_device_task_return_in_idle_cb (gpointer user_data)
break;
case FP_DEVICE_TASK_RETURN_OBJECT:
g_task_return_pointer (task, data->result, g_object_unref);
g_task_return_pointer (task, g_steal_pointer (&data->result),
g_object_unref);
break;
case FP_DEVICE_TASK_RETURN_PTR_ARRAY:
g_task_return_pointer (task, data->result,
g_task_return_pointer (task, g_steal_pointer (&data->result),
(GDestroyNotify) g_ptr_array_unref);
break;
case FP_DEVICE_TASK_RETURN_ERROR:
g_task_return_error (task, data->result);
g_task_return_error (task, g_steal_pointer (&data->result));
break;
default:
@@ -735,6 +799,30 @@ fp_device_task_return_in_idle_cb (gpointer user_data)
static void
fpi_device_task_return_data_free (FpDeviceTaskReturnData *data)
{
if (data->result)
{
switch (data->type)
{
case FP_DEVICE_TASK_RETURN_INT:
case FP_DEVICE_TASK_RETURN_BOOL:
break;
case FP_DEVICE_TASK_RETURN_OBJECT:
g_clear_object ((GObject **) &data->result);
break;
case FP_DEVICE_TASK_RETURN_PTR_ARRAY:
g_clear_pointer ((GPtrArray **) &data->result, g_ptr_array_unref);
break;
case FP_DEVICE_TASK_RETURN_ERROR:
g_clear_error ((GError **) &data->result);
break;
default:
g_assert_not_reached ();
}
}
g_object_unref (data->device);
g_free (data);
}
@@ -787,6 +875,7 @@ fpi_device_probe_complete (FpDevice *device,
g_debug ("Device reported probe completion");
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
if (!error)
{
@@ -829,6 +918,7 @@ fpi_device_open_complete (FpDevice *device, GError *error)
g_debug ("Device reported open completion");
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
if (!error)
{
@@ -862,6 +952,7 @@ fpi_device_close_complete (FpDevice *device, GError *error)
g_debug ("Device reported close completion");
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
switch (priv->type)
{
@@ -885,17 +976,17 @@ fpi_device_close_complete (FpDevice *device, GError *error)
return;
}
/* Always consider the device closed. Drivers should try hard to close the
* device. Generally, e.g. cancellations should be ignored.
*/
priv->is_open = FALSE;
g_object_notify (G_OBJECT (device), "open");
if (!error)
{
priv->is_open = FALSE;
g_object_notify (G_OBJECT (device), "open");
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
GUINT_TO_POINTER (TRUE));
}
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
GUINT_TO_POINTER (TRUE));
else
{
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
}
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
}
/**
@@ -918,12 +1009,14 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
g_debug ("Device reported enroll completion");
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
if (!error)
{
if (FP_IS_PRINT (print))
{
FpiPrintType print_type;
g_autofree char *finger_str = NULL;
g_object_get (print, "fpi-type", &print_type, NULL);
if (print_type == FPI_PRINT_UNDEFINED)
@@ -937,6 +1030,9 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
return;
}
finger_str = g_enum_to_string (FP_TYPE_FINGER, fp_print_get_finger (print));
g_debug ("Print for finger %s enrolled", finger_str);
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_OBJECT, print);
}
else
@@ -985,6 +1081,7 @@ fpi_device_verify_complete (FpDevice *device,
data = g_task_get_task_data (priv->current_task);
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
if (!error)
{
@@ -1044,6 +1141,7 @@ fpi_device_identify_complete (FpDevice *device,
data = g_task_get_task_data (priv->current_task);
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
if (!error)
{
@@ -1100,6 +1198,7 @@ fpi_device_capture_complete (FpDevice *device,
g_debug ("Device reported capture completion");
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
if (!error)
{
@@ -1145,6 +1244,7 @@ fpi_device_delete_complete (FpDevice *device,
g_debug ("Device reported deletion completion");
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
if (!error)
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
@@ -1179,6 +1279,7 @@ fpi_device_list_complete (FpDevice *device,
g_debug ("Device reported listing completion");
clear_device_cancel_action (device);
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
if (prints && error)
{
@@ -1394,3 +1495,59 @@ fpi_device_identify_report (FpDevice *device,
if (call_cb && data->match_cb)
data->match_cb (device, data->match, data->print, data->match_data, data->error);
}
/**
* fpi_device_report_finger_status:
* @device: The #FpDevice
* @finger_status: The current #FpFingerStatusFlags to report
*
* Report the finger status for the @device.
* This can be used by UI to give a feedback
*
* Returns: %TRUE if changed
*/
gboolean
fpi_device_report_finger_status (FpDevice *device,
FpFingerStatusFlags finger_status)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
g_autofree char *status_string = NULL;
if (priv->finger_status == finger_status)
return FALSE;
status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, finger_status);
fp_dbg ("Device reported finger status change: %s", status_string);
priv->finger_status = finger_status;
g_object_notify (G_OBJECT (device), "finger-status");
return TRUE;
}
/**
* fpi_device_report_finger_status_changes:
* @device: The #FpDevice
* @added_status: The #FpFingerStatusFlags to add
* @added_status: The #FpFingerStatusFlags to remove
*
* Report the finger status for the @device adding the @added_status flags
* and removing the @removed_status flags.
*
* This can be used by UI to give a feedback
*
* Returns: %TRUE if changed
*/
gboolean
fpi_device_report_finger_status_changes (FpDevice *device,
FpFingerStatusFlags added_status,
FpFingerStatusFlags removed_status)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpFingerStatusFlags finger_status = priv->finger_status;
finger_status |= added_status;
finger_status &= ~removed_status;
return fpi_device_report_finger_status (device, finger_status);
}
+7
View File
@@ -210,6 +210,7 @@ void fpi_device_get_delete_data (FpDevice *device,
FpPrint **print);
GCancellable *fpi_device_get_cancellable (FpDevice *device);
void fpi_device_remove (FpDevice *device);
GSource * fpi_device_add_timeout (FpDevice *device,
gint interval,
@@ -263,4 +264,10 @@ void fpi_device_identify_report (FpDevice *device,
FpPrint *print,
GError *error);
gboolean fpi_device_report_finger_status (FpDevice *device,
FpFingerStatusFlags finger_status);
gboolean fpi_device_report_finger_status_changes (FpDevice *device,
FpFingerStatusFlags added_status,
FpFingerStatusFlags removed_status);
G_END_DECLS
+191 -99
View File
@@ -41,6 +41,9 @@ fp_image_device_get_instance_private (FpImageDevice *self)
g_type_class_get_instance_private_offset (img_class));
}
static void fp_image_device_change_state (FpImageDevice *self,
FpiImageDeviceState state);
/* Private shared functions */
void
@@ -51,67 +54,105 @@ fpi_image_device_activate (FpImageDevice *self)
g_assert (!priv->active);
/* We don't have a neutral ACTIVE state, but we always will
* go into WAIT_FINGER_ON afterwards. */
priv->state = FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
/* We might have been waiting for deactivation to finish before
* starting the next operation. */
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
fp_dbg ("Activating image device\n");
fp_dbg ("Activating image device");
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_ACTIVATING);
cls->activate (self);
}
void
fpi_image_device_deactivate (FpImageDevice *self)
fpi_image_device_deactivate (FpImageDevice *self, gboolean cancelling)
{
FpDevice *device = FP_DEVICE (self);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
if (!priv->active)
if (!priv->active || priv->state == FPI_IMAGE_DEVICE_STATE_DEACTIVATING)
{
/* XXX: We currently deactivate both from minutiae scan result
* and finger off report. */
fp_dbg ("Already deactivated, ignoring request.");
return;
}
if (!priv->cancelling && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
g_warning ("Deactivating image device while waiting for finger, this should not happen.");
if (!cancelling && priv->state != FPI_IMAGE_DEVICE_STATE_IDLE)
g_warning ("Deactivating image device while it is not idle, this should not happen.");
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
fp_dbg ("Deactivating image device\n");
fp_dbg ("Deactivating image device");
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_DEACTIVATING);
cls->deactivate (self);
}
/* Static helper functions */
/* This should not be called directly to activate/deactivate the device! */
static void
fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
g_autofree char *prev_state_str = NULL;
g_autofree char *state_str = NULL;
gboolean transition_is_valid = FALSE;
gint i;
/* Cannot change to inactive using this function. */
g_assert (state != FPI_IMAGE_DEVICE_STATE_INACTIVE);
struct
{
FpiImageDeviceState from;
FpiImageDeviceState to;
} valid_transitions[] = {
{ FPI_IMAGE_DEVICE_STATE_INACTIVE, FPI_IMAGE_DEVICE_STATE_ACTIVATING },
/* We might have been waiting for the finger to go OFF to start the
* next operation. */
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
{ FPI_IMAGE_DEVICE_STATE_ACTIVATING, FPI_IMAGE_DEVICE_STATE_IDLE },
{ FPI_IMAGE_DEVICE_STATE_ACTIVATING, FPI_IMAGE_DEVICE_STATE_INACTIVE },
{ FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON },
{ FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_CAPTURE }, /* raw mode -- currently not supported */
{ FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_DEACTIVATING },
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON, FPI_IMAGE_DEVICE_STATE_CAPTURE },
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
{ FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF },
{ FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_IDLE }, /* raw mode -- currently not supported */
{ FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF, FPI_IMAGE_DEVICE_STATE_IDLE },
{ FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
{ FPI_IMAGE_DEVICE_STATE_DEACTIVATING, FPI_IMAGE_DEVICE_STATE_INACTIVE },
};
prev_state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, priv->state);
state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, state);
fp_dbg ("Image device internal state change from %s to %s\n",
fp_dbg ("Image device internal state change from %s to %s",
prev_state_str, state_str);
for (i = 0; i < G_N_ELEMENTS (valid_transitions); i++)
{
if (valid_transitions[i].from == priv->state && valid_transitions[i].to == state)
{
transition_is_valid = TRUE;
break;
}
}
if (!transition_is_valid)
g_warning ("Internal state machine issue: transition from %s to %s should not happen!",
prev_state_str, state_str);
priv->state = state;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
g_signal_emit_by_name (self, "fpi-image-device-state-changed", priv->state);
if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
{
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_NEEDED,
FP_FINGER_STATUS_NONE);
}
else if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
{
fpi_device_report_finger_status_changes (FP_DEVICE (self),
FP_FINGER_STATUS_NONE,
FP_FINGER_STATUS_NEEDED);
}
}
static void
@@ -119,15 +160,75 @@ fp_image_device_enroll_maybe_await_finger_on (FpImageDevice *self)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
if (priv->enroll_await_on_pending)
/* We wait for both the minutiae scan to complete and the finger to
* be removed before we switch to AWAIT_FINGER_ON. */
if (priv->minutiae_scan_active || priv->finger_present)
return;
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
}
static void
fp_image_device_maybe_complete_action (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpDevice *device = FP_DEVICE (self);
FpiDeviceAction action;
if (error)
{
priv->enroll_await_on_pending = FALSE;
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
/* Keep the first error we encountered, but not if it is of type retry */
if (priv->action_error && !(priv->action_error->domain == FP_DEVICE_RETRY))
{
g_warning ("Will complete with first error, new error was: %s", error->message);
g_clear_error (&error);
}
else
{
g_clear_error (&priv->action_error);
priv->action_error = error;
}
}
/* Do not complete if the device is still active or a minutiae scan is pending. */
if (priv->active || priv->minutiae_scan_active)
return;
if (!priv->action_error)
g_cancellable_set_error_if_cancelled (fpi_device_get_cancellable (device), &priv->action_error);
if (priv->action_error)
{
fpi_device_action_error (device, g_steal_pointer (&priv->action_error));
g_clear_object (&priv->capture_image);
return;
}
/* We are done, report the result. */
action = fpi_device_get_current_action (FP_DEVICE (self));
if (action == FPI_DEVICE_ACTION_ENROLL)
{
FpPrint *enroll_print;
fpi_device_get_enroll_data (device, &enroll_print);
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
}
else if (action == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_complete (device, NULL);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_identify_complete (device, NULL);
}
else if (action == FPI_DEVICE_ACTION_CAPTURE)
{
fpi_device_capture_complete (device, g_steal_pointer (&priv->capture_image), NULL);
}
else
{
fp_dbg ("Awaiting finger on");
priv->enroll_await_on_pending = TRUE;
g_assert_not_reached ();
}
}
@@ -143,14 +244,16 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
FpiDeviceAction action;
/* Note: We rely on the device to not disappear during an operation. */
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
priv->minutiae_scan_active = FALSE;
if (!fp_image_detect_minutiae_finish (image, res, &error))
{
/* Cancel operation . */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
fpi_device_action_error (device, g_steal_pointer (&error));
fpi_image_device_deactivate (self);
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
fpi_image_device_deactivate (self, TRUE);
return;
}
@@ -161,13 +264,12 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry");
}
priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
action = fpi_device_get_current_action (device);
if (action == FPI_DEVICE_ACTION_CAPTURE)
{
fpi_device_capture_complete (device, g_steal_pointer (&image), error);
fpi_image_device_deactivate (self);
priv->capture_image = g_steal_pointer (&image);
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
return;
}
@@ -181,8 +283,9 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
if (error->domain != FP_DEVICE_RETRY)
{
fpi_device_action_error (device, error);
fpi_image_device_deactivate (self);
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
/* We might not yet be deactivating, if we are enrolling. */
fpi_image_device_deactivate (self, TRUE);
return;
}
}
@@ -205,8 +308,8 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
/* Start another scan or deactivate. */
if (priv->enroll_stage == IMG_ENROLL_STAGES)
{
fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
fpi_image_device_deactivate (self);
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
fpi_image_device_deactivate (self, FALSE);
}
else
{
@@ -226,8 +329,8 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
if (!error || error->domain == FP_DEVICE_RETRY)
fpi_device_verify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
fpi_device_verify_complete (device, error);
fpi_image_device_deactivate (self);
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
@@ -249,8 +352,8 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
if (!error || error->domain == FP_DEVICE_RETRY)
fpi_device_identify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
fpi_device_identify_complete (device, error);
fpi_image_device_deactivate (self);
fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
}
else
{
@@ -305,6 +408,19 @@ fpi_image_device_report_finger_status (FpImageDevice *self,
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
if (present)
{
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_PRESENT,
FP_FINGER_STATUS_NONE);
}
else
{
fpi_device_report_finger_status_changes (device,
FP_FINGER_STATUS_NONE,
FP_FINGER_STATUS_PRESENT);
}
if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
{
/* Do we really want to always ignore such reports? We could
@@ -323,27 +439,23 @@ fpi_image_device_report_finger_status (FpImageDevice *self,
g_debug ("Image device reported finger status: %s", present ? "on" : "off");
priv->finger_present = present;
if (present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
{
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_CAPTURE);
}
else if (!present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
{
/* We need to deactivate or continue to await finger */
/* There are three possible situations:
* 1. We are deactivating the device and the action is still in progress
* (minutiae detection).
* 2. We are still deactivating the device after an action completed
* 3. We were waiting for finger removal to start the new action
* Either way, we always end up deactivating except for the enroll case.
/* If we are in the non-enroll case, we always deactivate.
*
* The enroll case is special as AWAIT_FINGER_ON should only happen after
* minutiae detection to prevent deactivation (without cancellation)
* from the AWAIT_FINGER_ON state.
* In the enroll case, the decision can only be made after minutiae
* detection has finished.
*/
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_IDLE);
if (action != FPI_DEVICE_ACTION_ENROLL)
fpi_image_device_deactivate (self);
fpi_image_device_deactivate (self, FALSE);
else
fp_image_device_enroll_maybe_await_finger_on (self);
}
@@ -378,16 +490,19 @@ fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
action == FPI_DEVICE_ACTION_IDENTIFY ||
action == FPI_DEVICE_ACTION_CAPTURE);
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
g_debug ("Image device captured an image");
priv->minutiae_scan_active = TRUE;
/* XXX: We also detect minutiae in capture mode, we solely do this
* to normalize the image which will happen as a by-product. */
fp_image_detect_minutiae (image,
fpi_device_get_cancellable (FP_DEVICE (self)),
fpi_image_device_minutiae_detected,
self);
/* XXX: This is wrong if we add support for raw capture mode. */
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
}
/**
@@ -423,36 +538,27 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
g_debug ("Reporting retry during enroll");
fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
/* Wait for finger removal and re-touch.
* TODO: Do we need to check that the finger is already off? */
priv->enroll_await_on_pending = TRUE;
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
}
else if (action == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_verify_complete (FP_DEVICE (self), NULL);
fp_image_device_maybe_complete_action (self, NULL);
fpi_image_device_deactivate (self, TRUE);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_identify_complete (FP_DEVICE (self), NULL);
fp_image_device_maybe_complete_action (self, NULL);
fpi_image_device_deactivate (self, TRUE);
}
else
{
/* We abort the operation and let the surrounding code retry in the
* non-enroll case (this is identical to a session error). */
g_debug ("Abort current operation due to retry (non-enroll case)");
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_action_error (FP_DEVICE (self), error);
/* The capture case where there is no early reporting. */
g_debug ("Abort current operation due to retry (no early-reporting)");
fp_image_device_maybe_complete_action (self, error);
fpi_image_device_deactivate (self, TRUE);
}
}
@@ -511,10 +617,8 @@ fpi_image_device_session_error (FpImageDevice *self, GError *error)
if (error->domain == FP_DEVICE_RETRY)
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_action_error (FP_DEVICE (self), error);
fp_image_device_maybe_complete_action (self, error);
fpi_image_device_deactivate (self, TRUE);
}
/**
@@ -533,6 +637,7 @@ fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
action = fpi_device_get_current_action (FP_DEVICE (self));
g_return_if_fail (priv->active == FALSE);
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_ACTIVATING);
g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
action == FPI_DEVICE_ACTION_VERIFY ||
action == FPI_DEVICE_ACTION_IDENTIFY ||
@@ -551,6 +656,7 @@ fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
/* We always want to capture at this point, move to AWAIT_FINGER
* state. */
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_IDLE);
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
}
@@ -565,36 +671,20 @@ void
fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error)
{
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
FpiDeviceAction action;
g_return_if_fail (priv->active == TRUE);
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE);
g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_DEACTIVATING);
g_debug ("Image device deactivation completed");
priv->active = FALSE;
/* Deactivation completed. As we deactivate in the background
* there may already be a new task pending. Check whether we
* need to do anything. */
action = fpi_device_get_current_action (FP_DEVICE (self));
/* Assume finger was removed. */
priv->finger_present = FALSE;
/* Special case, if we should be closing, but didn't due to a running
* deactivation, then do so now. */
if (action == FPI_DEVICE_ACTION_CLOSE)
{
cls->img_close (self);
return;
}
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_INACTIVE);
/* We might be waiting to be able to activate again. */
if (priv->pending_activation_timeout_id)
{
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
priv->pending_activation_timeout_id =
g_idle_add ((GSourceFunc) fpi_image_device_activate, self);
}
fp_image_device_maybe_complete_action (self, error);
}
/**
@@ -620,6 +710,8 @@ fpi_image_device_open_complete (FpImageDevice *self, GError *error)
priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
g_object_notify (G_OBJECT (self), "fpi-image-device-state");
fpi_device_report_finger_status (FP_DEVICE (self), FP_FINGER_STATUS_NONE);
fpi_device_open_complete (FP_DEVICE (self), error);
}
+27 -5
View File
@@ -25,6 +25,9 @@
/**
* FpiImageDeviceState:
* @FPI_IMAGE_DEVICE_STATE_INACTIVE: inactive
* @FPI_IMAGE_DEVICE_STATE_ACTIVATING: State during activate callback
* @FPI_IMAGE_DEVICE_STATE_IDLE: Activated but idle
* @FPI_IMAGE_DEVICE_STATE_DEACTIVATING: State during deactivate callback
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
* @FPI_IMAGE_DEVICE_STATE_CAPTURE: capturing an image
* @FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
@@ -35,9 +38,33 @@
* The driver needs to call fpi_image_device_report_finger_status() to move
* between the different states. Note that the capture state might be entered
* unconditionally if the device supports raw capturing.
*
* A usual run would look like:
* - inactive -> activating: activate vfunc is called
* - activating -> idle: fpi_image_device_activate_complete()
* - idle -> await-finger-on
* - await-finger-on -> capture: fpi_image_device_report_finger_status()
* - capture -> await-finger-off: fpi_image_device_image_captured()
* - await-finger-off -> idle: fpi_image_device_report_finger_status()
* - idle -> deactivating: deactivate vfunc is called
* - deactivating -> inactive: fpi_image_device_deactivate_complete()
*
* Raw mode is currently not supported (not waiting for finger), but in that
* case the following transitions are valid:
* - idle -> capture
* - capture -> idle
*
* Also valid are these transitions in case of errors or cancellations:
* - activating -> inactive: fpi_image_device_activate_complete()
* - await-finger-on -> deactivating: deactivate vfunc is called
* - capture -> deactivating: deactivate vfunc is called
* - await-finger-off -> deactivating: deactivate vfunc is called
*/
typedef enum {
FPI_IMAGE_DEVICE_STATE_INACTIVE,
FPI_IMAGE_DEVICE_STATE_ACTIVATING,
FPI_IMAGE_DEVICE_STATE_DEACTIVATING,
FPI_IMAGE_DEVICE_STATE_IDLE,
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON,
FPI_IMAGE_DEVICE_STATE_CAPTURE,
FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF,
@@ -58,11 +85,6 @@ typedef enum {
* finger or image capture). Implementing this is optional, it can e.g. be
* used to flash an LED when waiting for a finger.
*
* These are the main entry points for image based drivers. For all but the
* change_state vfunc, implementations *must* eventually call the corresponding
* function to finish the operation. It is also acceptable to call the generic
*
*
* These are the main entry points for drivers to implement. Drivers may not
* implement all of these entry points if they do not support the operation
* (or a default implementation is sufficient).
+30
View File
@@ -354,6 +354,24 @@ transfer_finish_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat
fpi_usb_transfer_unref (transfer);
}
static gboolean
transfer_cancel_cb (FpiUsbTransfer *transfer)
{
GError *error;
FpiUsbTransferCallback callback;
error = g_error_new_literal (G_IO_ERROR,
G_IO_ERROR_CANCELLED,
"Transfer was cancelled before being started");
callback = transfer->callback;
transfer->callback = NULL;
transfer->actual_length = -1;
callback (transfer, transfer->device, transfer->user_data, error);
fpi_usb_transfer_unref (transfer);
return G_SOURCE_REMOVE;
}
/**
* fpi_usb_transfer_submit:
@@ -387,6 +405,18 @@ fpi_usb_transfer_submit (FpiUsbTransfer *transfer,
log_transfer (transfer, TRUE, NULL);
/* Work around libgusb cancellation issue, see
* https://github.com/hughsie/libgusb/pull/42
* should be fixed with libgusb 0.3.7.
* Note that this is not race free, we rely on libfprint and API users
* not cancelling from a different thread here.
*/
if (cancellable && g_cancellable_is_cancelled (cancellable))
{
g_idle_add ((GSourceFunc) transfer_cancel_cb, transfer);
return;
}
switch (transfer->type)
{
case FP_TRANSFER_BULK:
+3
View File
@@ -20,6 +20,7 @@
#pragma once
#include <gusb.h>
#include "fpi-compat.h"
#include "fpi-device.h"
G_BEGIN_DECLS
@@ -119,6 +120,7 @@ void fpi_usb_transfer_fill_bulk (FpiUsbTransfer *transfer,
guint8 endpoint,
gsize length);
FP_GNUC_ACCESS (read_only, 3, 4)
void fpi_usb_transfer_fill_bulk_full (FpiUsbTransfer *transfer,
guint8 endpoint,
guint8 *buffer,
@@ -138,6 +140,7 @@ void fpi_usb_transfer_fill_interrupt (FpiUsbTransfer *transfer,
guint8 endpoint,
gsize length);
FP_GNUC_ACCESS (read_only, 3, 4)
void fpi_usb_transfer_fill_interrupt_full (FpiUsbTransfer *transfer,
guint8 endpoint,
guint8 *buffer,
+70 -3
View File
@@ -25,11 +25,78 @@
#include "fpi-device.h"
static const FpIdEntry whitelist_id_table[] = {
/* Unsupported (for now) Validity Sensors finger print readers */
{ .vid = 0x138a, .pid = 0x0090 }, /* Found on e.g. Lenovo T460s */
/* Currently known and unsupported devices.
* You can generate this list from the wiki page using e.g.:
* gio cat https://gitlab.freedesktop.org/libfprint/wiki/-/wikis/Unsupported-Devices.md | sed -n 's!|.*\([0-9a-fA-F]\{4\}\):\([0-9a-fA-F]\{4\}\).*|.*! { .vid = 0x\1, .pid = 0x\2 },!p'
*/
{ .vid = 0x04f3, .pid = 0x036b },
{ .vid = 0x04f3, .pid = 0x0c00 },
{ .vid = 0x04f3, .pid = 0x0c4b },
{ .vid = 0x04f3, .pid = 0x0c4c },
{ .vid = 0x04f3, .pid = 0x0c4f },
{ .vid = 0x04f3, .pid = 0x0c57 },
{ .vid = 0x04f3, .pid = 0x2706 },
{ .vid = 0x06cb, .pid = 0x0081 },
{ .vid = 0x06cb, .pid = 0x0088 },
{ .vid = 0x06cb, .pid = 0x008a },
{ .vid = 0x06cb, .pid = 0x009a },
{ .vid = 0x06cb, .pid = 0x009b },
{ .vid = 0x06cb, .pid = 0x00a2 },
{ .vid = 0x06cb, .pid = 0x00b7 },
{ .vid = 0x06cb, .pid = 0x00bb },
{ .vid = 0x06cb, .pid = 0x00be },
{ .vid = 0x06cb, .pid = 0x00c2 },
{ .vid = 0x06cb, .pid = 0x00c9 },
{ .vid = 0x06cb, .pid = 0x00cb },
{ .vid = 0x06cb, .pid = 0x00d8 },
{ .vid = 0x06cb, .pid = 0x00da },
{ .vid = 0x06cb, .pid = 0x00e7 },
{ .vid = 0x0a5c, .pid = 0x5801 },
{ .vid = 0x0a5c, .pid = 0x5805 },
{ .vid = 0x0a5c, .pid = 0x5834 },
{ .vid = 0x0a5c, .pid = 0x5843 },
{ .vid = 0x10a5, .pid = 0x0007 },
{ .vid = 0x1188, .pid = 0x9545 },
{ .vid = 0x138a, .pid = 0x0007 },
{ .vid = 0x138a, .pid = 0x003a },
{ .vid = 0x138a, .pid = 0x003c },
{ .vid = 0x138a, .pid = 0x003d },
{ .vid = 0x138a, .pid = 0x003f },
{ .vid = 0x138a, .pid = 0x0090 },
{ .vid = 0x138a, .pid = 0x0091 },
{ .vid = 0x138a, .pid = 0x0092 },
{ .vid = 0x138a, .pid = 0x0094 },
{ .vid = 0x138a, .pid = 0x0097 }, /* Found on e.g. Lenovo T470s */
{ .vid = 0x138a, .pid = 0x0097 },
{ .vid = 0x138a, .pid = 0x009d },
{ .vid = 0x138a, .pid = 0x00ab },
{ .vid = 0x147e, .pid = 0x1002 },
{ .vid = 0x1491, .pid = 0x0088 },
{ .vid = 0x16d1, .pid = 0x1027 },
{ .vid = 0x1c7a, .pid = 0x0300 },
{ .vid = 0x1c7a, .pid = 0x0570 },
{ .vid = 0x1c7a, .pid = 0x0575 },
{ .vid = 0x27c6, .pid = 0x5042 },
{ .vid = 0x27c6, .pid = 0x5110 },
{ .vid = 0x27c6, .pid = 0x5117 },
{ .vid = 0x27c6, .pid = 0x5201 },
{ .vid = 0x27c6, .pid = 0x521d },
{ .vid = 0x27c6, .pid = 0x5301 },
{ .vid = 0x27c6, .pid = 0x530c },
{ .vid = 0x27c6, .pid = 0x532d },
{ .vid = 0x27c6, .pid = 0x533c },
{ .vid = 0x27c6, .pid = 0x5381 },
{ .vid = 0x27c6, .pid = 0x5385 },
{ .vid = 0x27c6, .pid = 0x538c },
{ .vid = 0x27c6, .pid = 0x538d },
{ .vid = 0x27c6, .pid = 0x5395 },
{ .vid = 0x27c6, .pid = 0x5584 },
{ .vid = 0x27c6, .pid = 0x55a2 },
{ .vid = 0x27c6, .pid = 0x55a4 },
{ .vid = 0x27c6, .pid = 0x55b4 },
{ .vid = 0x27c6, .pid = 0x5740 },
{ .vid = 0x2808, .pid = 0x9338 },
{ .vid = 0x298d, .pid = 0x2033 },
{ .vid = 0x3538, .pid = 0x0930 },
{ .vid = 0 },
};