GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/synaptics/synaptics.c
Date: 2025-03-01 04:11:53
Exec Total Coverage
Lines: 433 728 59.5%
Functions: 28 35 80.0%
Branches: 128 307 41.7%

Line Branch Exec Source
1 /*
2 * Copyright (C) 2019 Synaptics Inc
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #define FP_COMPONENT "synaptics"
20
21 #include "drivers_api.h"
22
23 #include "fpi-byte-reader.h"
24
25 #include "synaptics.h"
26 #include "bmkt_message.h"
27
28
3/4
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
387 G_DEFINE_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FP_TYPE_DEVICE)
29
30 static void init_identify_msg (FpDevice *device);
31 static void compose_and_send_identify_msg (FpDevice *device);
32
33 static const FpIdEntry id_table[] = {
34 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00BD, },
35 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C2, },
36 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C4, },
37 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C6, },
38 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00DF, },
39 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F0, },
40 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F9, },
41 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00FC, },
42 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0100, },
43 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0103, },
44 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0104, },
45 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0106, },
46 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0107, },
47 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0108, },
48 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0123, },
49 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0124, },
50 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0126, },
51 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0129, },
52 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x015F, },
53 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0168, },
54 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x016C, },
55 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0173, },
56 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0174, },
57 { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x019D, },
58 { .vid = 0, .pid = 0, .driver_data = 0 }, /* terminating entry */
59 };
60
61
62 static void
63 52 cmd_receive_cb (FpiUsbTransfer *transfer,
64 FpDevice *device,
65 gpointer user_data,
66 GError *error)
67 {
68 52 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
69 52 SynCmdMsgCallback callback = user_data;
70 52 int res;
71 52 bmkt_msg_resp_t msg_resp;
72 52 bmkt_response_t resp;
73
74
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (error)
75 {
76 /* NOTE: assumes timeout should never happen for receiving. */
77 fpi_ssm_mark_failed (transfer->ssm, error);
78 22 return;
79 }
80
81 104 res = bmkt_parse_message_header (&transfer->buffer[SENSOR_FW_REPLY_HEADER_LEN],
82 52 transfer->actual_length - SENSOR_FW_REPLY_HEADER_LEN,
83 &msg_resp);
84
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (res != BMKT_SUCCESS)
85 {
86 g_warning ("Corrupted message received");
87 fpi_ssm_mark_failed (transfer->ssm,
88 fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
89 return;
90 }
91
92 /* Special case events */
93
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 30 times.
52 if (msg_resp.msg_id == BMKT_EVT_FINGER_REPORT)
94 {
95
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (msg_resp.payload_len != 1)
96 {
97 g_warning ("Corrupted finger report received");
98 fpi_ssm_mark_failed (transfer->ssm,
99 fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
100 return;
101 }
102
103
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
22 if (msg_resp.payload[0] == 0x01)
104 {
105 11 self->finger_on_sensor = TRUE;
106 11 fpi_device_report_finger_status_changes (device,
107 FP_FINGER_STATUS_PRESENT,
108 FP_FINGER_STATUS_NONE);
109 }
110 else
111 {
112 11 self->finger_on_sensor = FALSE;
113 11 fpi_device_report_finger_status_changes (device,
114 FP_FINGER_STATUS_NONE,
115 FP_FINGER_STATUS_PRESENT);
116
117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (self->cmd_complete_on_removal)
118 {
119 if (self->delay_error)
120 fpi_ssm_mark_failed (transfer->ssm,
121 g_steal_pointer (&self->delay_error));
122 else
123 fpi_ssm_mark_completed (transfer->ssm);
124 return;
125 }
126 }
127
128
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
33 fp_dbg ("Finger is now %s the sensor", self->finger_on_sensor ? "on" : "off");
129
130 /* XXX: Call callback!?! */
131 }
132
133 52 res = bmkt_parse_message_payload (&msg_resp, &resp);
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (res != BMKT_SUCCESS)
135 {
136 g_warning ("Could not parse message payload: %i", res);
137 fpi_ssm_mark_failed (transfer->ssm,
138 fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
139 return;
140 }
141
142 /* Special cancellation handling */
143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (resp.response_id == BMKT_RSP_CANCEL_OP_OK || resp.response_id == BMKT_RSP_CANCEL_OP_FAIL)
144 {
145 if (resp.response_id == BMKT_RSP_CANCEL_OP_OK)
146 {
147 fp_dbg ("Received cancellation success response");
148 fpi_ssm_mark_failed (transfer->ssm,
149 g_error_new_literal (G_IO_ERROR,
150 G_IO_ERROR_CANCELLED,
151 "Device reported cancellation of operation"));
152 }
153 else
154 {
155 fp_dbg ("Cancellation failed, this should not happen");
156 fpi_ssm_mark_failed (transfer->ssm,
157 fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
158 }
159 return;
160 }
161
162
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 30 times.
52 if (msg_resp.seq_num == 0)
163 {
164 /* XXX: Should we really abort the command on general error?
165 * The original code did not! */
166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (msg_resp.msg_id == BMKT_RSP_GENERAL_ERROR)
167 {
168 guint16 err;
169
170 /* XXX: It is weird that this is big endian. */
171 err = FP_READ_UINT16_BE (msg_resp.payload);
172
173 fp_warn ("Received General Error %d from the sensor", (guint) err);
174 fpi_ssm_mark_failed (transfer->ssm,
175 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
176 "Received general error %u from device",
177 (guint) err));
178 //fpi_ssm_jump_to_state (transfer->ssm, fpi_ssm_get_cur_state (transfer->ssm));
179 return;
180 }
181 else
182 {
183 22 fp_dbg ("Received message with 0 sequence number 0x%02x, ignoring!",
184 msg_resp.msg_id);
185 22 fpi_ssm_next_state (transfer->ssm);
186 22 return;
187 }
188 }
189
190 /* We should only ever have one command running, and the sequence num needs
191 * to match. */
192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (msg_resp.seq_num != self->cmd_seq_num)
193 {
194 fp_warn ("Got unexpected sequence number from device, %d instead of %d",
195 msg_resp.seq_num,
196 self->cmd_seq_num);
197 }
198
199
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 if (callback)
200 30 callback (self, &resp, NULL);
201
202 /* Callback may have queued a follow up command, then we need
203 * to restart the SSM. If not, we'll finish/wait for interrupt
204 * depending on resp.complete. */
205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (self->cmd_pending_transfer)
206 fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_SEND_PENDING);
207
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
30 else if (!resp.complete || self->cmd_complete_on_removal)
208 23 fpi_ssm_next_state (transfer->ssm); /* SYNAPTICS_CMD_WAIT_INTERRUPT */
209 else
210 7 fpi_ssm_mark_completed (transfer->ssm);
211 }
212
213 static void
214 46 cmd_interrupt_cb (FpiUsbTransfer *transfer,
215 FpDevice *device,
216 gpointer user_data,
217 GError *error)
218 {
219 46 g_debug ("interrupt transfer done");
220 46 fpi_device_critical_enter (device);
221
222
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 45 times.
46 if (error)
223 {
224
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
225 {
226 1 g_error_free (error);
227
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (FPI_DEVICE_SYNAPTICS (device)->cmd_suspended)
228 1 fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_SUSPENDED);
229 else
230 fpi_ssm_jump_to_state (transfer->ssm, SYNAPTICS_CMD_GET_RESP);
231 1 return;
232 }
233
234 fpi_ssm_mark_failed (transfer->ssm, error);
235 return;
236 }
237
238
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45 if (transfer->buffer[0] & USB_ASYNC_MESSAGE_PENDING)
239 {
240 45 fpi_ssm_next_state (transfer->ssm);
241 }
242 else
243 {
244 fpi_device_critical_leave (device);
245 fpi_usb_transfer_submit (fpi_usb_transfer_ref (transfer),
246 0,
247 NULL,
248 cmd_interrupt_cb,
249 NULL);
250 }
251 }
252
253 static void
254 242 synaptics_cmd_run_state (FpiSsm *ssm,
255 FpDevice *dev)
256 {
257 242 FpiUsbTransfer *transfer;
258 242 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
259
260
7/8
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 45 times.
✓ Branch 4 taken 45 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
242 switch (fpi_ssm_get_cur_state (ssm))
261 {
262 52 case SYNAPTICS_CMD_SEND_PENDING:
263
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 45 times.
52 if (self->cmd_pending_transfer)
264 {
265 7 self->cmd_pending_transfer->ssm = ssm;
266 7 fpi_usb_transfer_submit (self->cmd_pending_transfer,
267 1000,
268 NULL,
269 fpi_ssm_usb_transfer_cb,
270 NULL);
271 7 self->cmd_pending_transfer = NULL;
272 }
273 else
274 {
275 45 fpi_ssm_next_state (ssm);
276 }
277 break;
278
279 52 case SYNAPTICS_CMD_GET_RESP:
280 52 transfer = fpi_usb_transfer_new (dev);
281 52 transfer->ssm = ssm;
282 52 fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, MAX_TRANSFER_LEN);
283 52 fpi_usb_transfer_submit (transfer,
284 5000,
285 NULL,
286 cmd_receive_cb,
287 fpi_ssm_get_data (ssm));
288
289 52 break;
290
291 46 case SYNAPTICS_CMD_WAIT_INTERRUPT:
292 /* Interruptions are permitted only during an interrupt transfer */
293 46 fpi_device_critical_leave (dev);
294
295 46 transfer = fpi_usb_transfer_new (dev);
296 46 transfer->ssm = ssm;
297 46 fpi_usb_transfer_fill_interrupt (transfer, USB_EP_INTERRUPT, USB_INTERRUPT_DATA_SIZE);
298 46 fpi_usb_transfer_submit (transfer,
299 0,
300 self->interrupt_cancellable,
301 cmd_interrupt_cb,
302 NULL);
303
304 46 break;
305
306 45 case SYNAPTICS_CMD_SEND_ASYNC:
307 45 transfer = fpi_usb_transfer_new (dev);
308 45 transfer->ssm = ssm;
309 45 fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN);
310 45 transfer->buffer[0] = SENSOR_CMD_ASYNCMSG_READ;
311 45 fpi_usb_transfer_submit (transfer,
312 1000,
313 NULL,
314 fpi_ssm_usb_transfer_cb,
315 NULL);
316
317 45 break;
318
319 45 case SYNAPTICS_CMD_RESTART:
320 45 fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_SEND_PENDING);
321 45 break;
322
323 1 case SYNAPTICS_CMD_SUSPENDED:
324 /* The resume handler continues to the next state! */
325 1 fpi_device_critical_leave (dev);
326 1 fpi_device_suspend_complete (dev, NULL);
327 1 break;
328
329 1 case SYNAPTICS_CMD_RESUME:
330 1 fpi_device_critical_enter (dev);
331 1 fpi_ssm_jump_to_state (ssm, SYNAPTICS_CMD_WAIT_INTERRUPT);
332 1 break;
333 }
334 242 }
335
336 static void
337 7 cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
338 {
339 7 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
340 7 SynCmdMsgCallback callback = fpi_ssm_get_data (ssm);
341
342 7 self->cmd_ssm = NULL;
343
344 /* Notify about the SSM failure from here instead. */
345
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (error || self->cmd_complete_on_removal)
346 callback (self, NULL, error);
347
348 7 fpi_device_critical_leave (dev);
349 7 self->cmd_complete_on_removal = FALSE;
350 7 }
351
352 static void
353 cmd_forget_cb (FpiUsbTransfer *transfer,
354 FpDevice *device,
355 gpointer user_data,
356 GError *error)
357 {
358 if (error)
359 {
360 g_warning ("Async command sending failed: %s", error->message);
361 g_error_free (error);
362 }
363 else
364 {
365 g_debug ("Async command sent successfully");
366 }
367 }
368
369 static void
370 7 synaptics_sensor_cmd (FpiDeviceSynaptics *self,
371 gint seq_num,
372 guint8 msg_id,
373 const guint8 * payload,
374 gssize payload_len,
375 SynCmdMsgCallback callback)
376 {
377 7 FpiUsbTransfer *transfer;
378 7 guint8 real_seq_num;
379 7 gint msg_len;
380 7 gint res;
381
382 /* callback may be NULL in two cases:
383 * - seq_num == -1
384 * - a state machine is already running, continued command */
385
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 g_assert (payload || payload_len == 0);
386
387 /* seq_num of 0 means a normal command, -1 means the current commands
388 * sequence number should not be updated (i.e. second async command which
389 * may only be a cancellation currently). */
390
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (seq_num <= 0)
391 {
392 7 self->last_seq_num = MAX (1, (self->last_seq_num + 1) & 0xff);
393 7 real_seq_num = self->last_seq_num;
394
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (seq_num == 0)
395 7 self->cmd_seq_num = self->last_seq_num;
396 }
397 else
398 {
399 real_seq_num = seq_num;
400 self->last_seq_num = real_seq_num;
401 }
402 7 g_debug ("sequence number is %d", real_seq_num);
403
404 /* We calculate the exact length here (we could also just create a larger
405 * buffer instead and check the result of bmkt_compose_message. */
406 7 msg_len = BMKT_MESSAGE_HEADER_LEN + payload_len;
407
408 /* Send out the command */
409 7 transfer = fpi_usb_transfer_new (FP_DEVICE (self));
410 7 transfer->short_is_error = TRUE;
411 7 fpi_usb_transfer_fill_bulk (transfer,
412 USB_EP_REQUEST,
413 7 msg_len + SENSOR_FW_CMD_HEADER_LEN);
414
415 /* MIS sensors send ACE commands encapsulated in FW commands*/
416 7 transfer->buffer[0] = SENSOR_CMD_ACE_COMMAND;
417 7 res = bmkt_compose_message (&transfer->buffer[1],
418 &msg_len, msg_id,
419 real_seq_num,
420 payload_len,
421 payload);
422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 g_assert (res == BMKT_SUCCESS);
423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 g_assert (msg_len + SENSOR_FW_CMD_HEADER_LEN == transfer->length);
424
425 /* Special case for async command sending (should only be used for
426 * cancellation). */
427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (seq_num == -1)
428 {
429 g_assert (callback == NULL);
430
431 /* We just send and forget here. */
432 fpi_usb_transfer_submit (transfer, 1000, NULL, cmd_forget_cb, NULL);
433 }
434 else
435 {
436 /* Command should be send using the state machine. */
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 g_assert (self->cmd_pending_transfer == NULL);
438
439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 self->cmd_pending_transfer = g_steal_pointer (&transfer);
440
441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (self->cmd_ssm)
442 {
443 /* Continued command, we already have an SSM with a callback.
444 * There is nothing to do in this case, the command will be
445 * sent automatically. */
446 g_assert (callback == NULL);
447 }
448 else
449 {
450 /* Start of a new command, create the state machine. */
451
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 g_assert (callback != NULL);
452
453 7 self->cmd_ssm = fpi_ssm_new (FP_DEVICE (self),
454 synaptics_cmd_run_state,
455 SYNAPTICS_CMD_NUM_STATES);
456 7 fpi_ssm_set_data (self->cmd_ssm, callback, NULL);
457
458 7 fpi_device_critical_enter (FP_DEVICE (self));
459 7 fpi_ssm_start (self->cmd_ssm, cmd_ssm_done);
460 }
461 }
462 7 }
463
464 static gboolean
465 2 parse_print_data (GVariant *data,
466 guint8 *finger,
467 const guint8 **user_id,
468 gsize *user_id_len)
469 {
470 4 g_autoptr(GVariant) user_id_var = NULL;
471
472
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 g_return_val_if_fail (data != NULL, FALSE);
473
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 g_return_val_if_fail (finger != NULL, FALSE);
474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 g_return_val_if_fail (user_id != NULL, FALSE);
475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 g_return_val_if_fail (user_id_len != NULL, FALSE);
476
477 2 *user_id = NULL;
478 2 *user_id_len = 0;
479
480
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!g_variant_check_format_string (data, "(y@ay)", FALSE))
481 return FALSE;
482
483 2 g_variant_get (data,
484 "(y@ay)",
485 finger,
486 &user_id_var);
487
488 2 *user_id = g_variant_get_fixed_array (user_id_var, user_id_len, 1);
489
490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (*user_id_len == 0 || *user_id_len > BMKT_MAX_USER_ID_LEN)
491 return FALSE;
492
493
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (*user_id_len <= 0 || *user_id[0] == ' ')
494 return FALSE;
495
496 return TRUE;
497 }
498
499 static FpPrint *
500 create_print (FpiDeviceSynaptics *self,
501 guint8 *user_id,
502 guint8 finger_id)
503 {
504 FpPrint *print;
505 g_autofree gchar *user_id_safe = NULL;
506 GVariant *data = NULL;
507 GVariant *uid = NULL;
508
509 user_id_safe = g_strndup ((char *) user_id, BMKT_MAX_USER_ID_LEN);
510
511 print = fp_print_new (FP_DEVICE (self));
512 uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
513 user_id_safe,
514 strlen (user_id_safe),
515 1);
516 data = g_variant_new ("(y@ay)",
517 finger_id,
518 uid);
519
520 fpi_print_set_type (print, FPI_PRINT_RAW);
521 fpi_print_set_device_stored (print, TRUE);
522 g_object_set (print, "fpi-data", data, NULL);
523 g_object_set (print, "description", user_id_safe, NULL);
524
525 fpi_print_fill_from_user_id (print, user_id_safe);
526
527 return print;
528 }
529
530 static void
531 1 verify_complete_after_finger_removal (FpiDeviceSynaptics *self)
532 {
533 1 FpDevice *device = FP_DEVICE (self);
534
535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (self->finger_on_sensor)
536 {
537 fp_dbg ("delaying verify report until after finger removal!");
538 self->cmd_complete_on_removal = TRUE;
539 }
540 else
541 {
542 1 fpi_device_verify_complete (device, NULL);
543 }
544 1 }
545
546 static void
547 3 verify_msg_cb (FpiDeviceSynaptics *self,
548 bmkt_response_t *resp,
549 GError *error)
550 {
551 3 FpDevice *device = FP_DEVICE (self);
552 3 bmkt_verify_resp_t *verify_resp;
553
554
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (self->action_starting)
555 {
556 1 fpi_device_critical_leave (device);
557 1 self->action_starting = FALSE;
558 }
559
560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (error)
561 {
562 fpi_device_verify_complete (device, error);
563 return;
564 }
565
566
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if (resp == NULL && self->cmd_complete_on_removal)
567 {
568 fpi_device_verify_complete (device, NULL);
569 return;
570 }
571
572 g_assert (resp != NULL);
573
574 3 verify_resp = &resp->response.verify_resp;
575
576
3/5
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
3 switch (resp->response_id)
577 {
578 1 case BMKT_RSP_VERIFY_READY:
579 1 fpi_device_report_finger_status_changes (device,
580 FP_FINGER_STATUS_NEEDED,
581 FP_FINGER_STATUS_NONE);
582 1 fp_info ("Place Finger on the Sensor!");
583 1 break;
584
585 1 case BMKT_RSP_CAPTURE_COMPLETE:
586 1 fp_info ("Fingerprint image capture complete!");
587 1 break;
588
589 case BMKT_RSP_VERIFY_FAIL:
590 if (resp->result == BMKT_SENSOR_STIMULUS_ERROR)
591 {
592 fp_info ("Match error occurred");
593 fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL,
594 fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
595 verify_complete_after_finger_removal (self);
596 }
597 else if (resp->result == BMKT_FP_NO_MATCH)
598 {
599 fp_info ("Print didn't match");
600 fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL);
601 verify_complete_after_finger_removal (self);
602 }
603 else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
604 {
605 fp_info ("Print is not in database");
606 fpi_device_verify_complete (device,
607 fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
608 }
609 else
610 {
611 fp_warn ("Verify has failed: %d", resp->result);
612 fpi_device_verify_complete (device,
613 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
614 "Unexpected result from device %d",
615 resp->result));
616 }
617 break;
618
619 1 case BMKT_RSP_VERIFY_OK:
620 1 fp_info ("Verify was successful! for user: %s finger: %d score: %f",
621 verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result);
622 1 fpi_device_verify_report (device, FPI_MATCH_SUCCESS, NULL, NULL);
623 1 verify_complete_after_finger_removal (self);
624 1 break;
625 }
626 }
627
628 static void
629 1 verify (FpDevice *device)
630 {
631 1 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
632 1 FpPrint *print = NULL;
633
634 1 g_autoptr(GVariant) data = NULL;
635 1 guint8 finger;
636 1 const guint8 *user_id;
637 1 gsize user_id_len = 0;
638
639 1 fpi_device_get_verify_data (device, &print);
640
641 1 g_object_get (print, "fpi-data", &data, NULL);
642 1 g_debug ("data is %p", data);
643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!parse_print_data (data, &finger, &user_id, &user_id_len))
644 {
645 fpi_device_verify_complete (device,
646 fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
647 return;
648 }
649
650 1 G_DEBUG_HERE ();
651
652 1 self->action_starting = TRUE;
653 1 fpi_device_critical_enter (device);
654
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 synaptics_sensor_cmd (self, 0, BMKT_CMD_VERIFY_USER, user_id, user_id_len, verify_msg_cb);
655 }
656
657 static void
658 identify_complete_after_finger_removal (FpiDeviceSynaptics *self, GError *error)
659 {
660 FpDevice *device = FP_DEVICE (self);
661
662 if (self->finger_on_sensor)
663 {
664 fp_dbg ("delaying identify report until after finger removal!");
665 if (error)
666 g_propagate_error (&self->delay_error, error);
667
668 self->cmd_complete_on_removal = TRUE;
669 }
670 else
671 {
672 fpi_device_identify_complete (device, error);
673 }
674 }
675
676
677 static void
678 identify_msg_cb (FpiDeviceSynaptics *self,
679 bmkt_response_t *resp,
680 GError *error)
681 {
682 FpDevice *device = FP_DEVICE (self);
683
684 if (self->action_starting)
685 {
686 fpi_device_critical_leave (device);
687 self->action_starting = FALSE;
688 }
689
690 if (error)
691 {
692 fpi_device_identify_complete (device, error);
693 return;
694 }
695
696 if (resp == NULL && self->cmd_complete_on_removal)
697 {
698 fpi_device_identify_complete (device, NULL);
699 return;
700 }
701
702 g_assert (resp != NULL);
703
704 switch (resp->response_id)
705 {
706 case BMKT_RSP_ID_READY:
707 fp_info ("Place Finger on the Sensor!");
708 break;
709
710 case BMKT_RSP_SEND_NEXT_USER_ID:
711 {
712 compose_and_send_identify_msg (device);
713 break;
714 }
715
716 case BMKT_RSP_ID_FAIL:
717 if (resp->result == BMKT_SENSOR_STIMULUS_ERROR)
718 {
719 fp_info ("Match error occurred");
720 fpi_device_identify_report (device, NULL, NULL,
721 fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
722 identify_complete_after_finger_removal (self, NULL);
723 }
724 else if (resp->result == BMKT_FP_NO_MATCH)
725 {
726 fp_info ("Print didn't match");
727 fpi_device_identify_report (device, NULL, NULL, NULL);
728 identify_complete_after_finger_removal (self, NULL);
729 }
730 else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS || resp->result == BMKT_FP_DATABASE_EMPTY)
731 {
732 fp_info ("Print is not in database");
733 identify_complete_after_finger_removal (self, fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
734 }
735 else
736 {
737 fp_warn ("identify has failed: %d", resp->result);
738 fpi_device_identify_complete (device,
739 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
740 "Unexpected result from device %d",
741 resp->result));
742 }
743 break;
744
745 case BMKT_RSP_ID_OK:
746 {
747 FpPrint *print = NULL;
748 GPtrArray *prints = NULL;
749 g_autoptr(GVariant) data = NULL;
750 gboolean found = FALSE;
751 guint index;
752
753 print = create_print (self,
754 resp->response.id_resp.user_id,
755 resp->response.id_resp.finger_id);
756
757 fpi_device_get_identify_data (device, &prints);
758
759 found = g_ptr_array_find_with_equal_func (prints,
760 print,
761 (GEqualFunc) fp_print_equal,
762 &index);
763
764 if (found)
765 fpi_device_identify_report (device, g_ptr_array_index (prints, index), print, NULL);
766 else
767 fpi_device_identify_report (device, NULL, print, NULL);
768
769 identify_complete_after_finger_removal (self, NULL);
770 }
771 }
772 }
773
774 static void
775 identify (FpDevice *device)
776 {
777 GPtrArray *prints = NULL;
778 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
779
780 fpi_device_get_identify_data (device, &prints);
781
782 /* Identify over no prints does not work for synaptics.
783 * This *may* make sense for other devices though, as identify may return
784 * a matched print even if it is not in the list of prints.
785 */
786 if (prints->len == 0)
787 {
788 fpi_device_identify_report (device, NULL, NULL, NULL);
789 fpi_device_identify_complete (device, NULL);
790 return;
791 }
792
793 self->action_starting = TRUE;
794 fpi_device_critical_enter (device);
795
796 init_identify_msg (device);
797 compose_and_send_identify_msg (device);
798 }
799
800 static void
801 init_identify_msg (FpDevice *device)
802 {
803 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
804
805 self->id_idx = 0;
806 }
807
808 static void
809 compose_and_send_identify_msg (FpDevice *device)
810 {
811 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
812 FpPrint *print = NULL;
813 GPtrArray *prints = NULL;
814
815 g_autoptr(GVariant) data = NULL;
816 guint8 finger;
817 const guint8 *user_id;
818 gsize user_id_len = 0;
819 g_autofree guint8 *payload = NULL;
820 guint8 payload_len = 0;
821 guint8 payloadOffset = 0;
822
823 fpi_device_get_identify_data (device, &prints);
824 if (prints->len > UINT8_MAX)
825 {
826 fpi_device_identify_complete (device,
827 fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
828 return;
829 }
830 if(self->id_idx >= prints->len)
831 {
832 fp_warn ("Device asked for more prints than we are providing.");
833 fpi_device_identify_complete (device,
834 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
835 "Unexpected index"));
836 return;
837 }
838 print = g_ptr_array_index (prints, self->id_idx);
839 g_object_get (print, "fpi-data", &data, NULL);
840 g_debug ("data is %p", data);
841 if (!parse_print_data (data, &finger, &user_id, &user_id_len))
842 {
843 fpi_device_identify_complete (device,
844 fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
845 return;
846 }
847 if(self->id_idx == 0)
848 {
849 /*
850 * Construct payload.
851 * 1st byte is total number of IDs in list.
852 * 2nd byte is number of IDs in list.
853 * 1 byte for each ID length, maximum id length is 100.
854 * user_id_len bytes of each ID
855 */
856 payload_len = 2 + 1 + user_id_len;
857 payload = g_malloc0 (payload_len);
858 payload[payloadOffset] = prints->len;
859 payloadOffset += 1;
860 payload[payloadOffset] = 1; /* send one id per message */
861 payloadOffset += 1;
862 payload[payloadOffset] = user_id_len;
863 payloadOffset += 1;
864 memcpy (&payload[payloadOffset], user_id, user_id_len);
865 payloadOffset += user_id_len;
866
867 G_DEBUG_HERE ();
868
869 synaptics_sensor_cmd (self, 0, BMKT_CMD_ID_USER_IN_ORDER, payload, payloadOffset, identify_msg_cb);
870 }
871 else
872 {
873 /*
874 * 1st byte is the number of IDs
875 * 1 byte for each ID length
876 * id_length bytes for each ID
877 */
878 payload_len = 1 + 1 + user_id_len;
879 payload = g_malloc0 (payload_len);
880 payload[payloadOffset] = 1; /* send one id per message */
881 payloadOffset += 1;
882 payload[payloadOffset] = user_id_len;
883 payloadOffset += 1;
884 memcpy (&payload[payloadOffset], user_id, user_id_len);
885 payloadOffset += user_id_len;
886 synaptics_sensor_cmd (self, self->cmd_seq_num, BMKT_CMD_ID_NEXT_USER, payload, payloadOffset, NULL);
887 }
888 self->id_idx++;
889 }
890 static void
891 20 enroll_msg_cb (FpiDeviceSynaptics *self,
892 bmkt_response_t *resp,
893 GError *error)
894 {
895 20 FpDevice *device = FP_DEVICE (self);
896 20 bmkt_enroll_resp_t *enroll_resp;
897
898
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 19 times.
20 if (self->action_starting)
899 {
900 1 fpi_device_critical_leave (device);
901 1 self->action_starting = FALSE;
902 }
903
904
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (error)
905 {
906 fpi_device_enroll_complete (device, NULL, error);
907 return;
908 }
909
910 20 enroll_resp = &resp->response.enroll_resp;
911
912
4/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
20 switch (resp->response_id)
913 {
914 1 case BMKT_RSP_ENROLL_READY:
915 {
916 1 self->enroll_stage = 0;
917 1 fpi_device_report_finger_status_changes (device,
918 FP_FINGER_STATUS_NEEDED,
919 FP_FINGER_STATUS_NONE);
920 1 fp_info ("Place Finger on the Sensor!");
921 1 break;
922 }
923
924 9 case BMKT_RSP_CAPTURE_COMPLETE:
925 {
926 9 fp_info ("Fingerprint image capture complete!");
927 9 break;
928 }
929
930 9 case BMKT_RSP_ENROLL_REPORT:
931 {
932 9 gint done_stages;
933 9 fp_info ("Enrollment is %d %% ", enroll_resp->progress);
934
935 9 done_stages = (enroll_resp->progress * ENROLL_SAMPLES + 99) / 100;
936
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 if (enroll_resp->progress < 100)
937 8 done_stages = MIN (done_stages, ENROLL_SAMPLES - 1);
938
939 /* Emit a retry error if there has been no discernible
940 * progress. Some firmware revisions report more required
941 * touches. */
942
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (self->enroll_stage == done_stages)
943 {
944 1 fpi_device_enroll_progress (device,
945 done_stages,
946 NULL,
947 fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
948 }
949
950
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 9 times.
17 while (self->enroll_stage < done_stages)
951 {
952 8 self->enroll_stage += 1;
953 8 fpi_device_enroll_progress (device, self->enroll_stage, NULL, NULL);
954 }
955 break;
956 }
957
958 case BMKT_RSP_ENROLL_PAUSED:
959 {
960 fp_info ("Enrollment has been paused!");
961 break;
962 }
963
964 case BMKT_RSP_ENROLL_RESUMED:
965 {
966 fp_info ("Enrollment has been resumed!");
967 break;
968 }
969
970 case BMKT_RSP_ENROLL_FAIL:
971 {
972 fp_info ("Enrollment has failed!: %d", resp->result);
973 if (resp->result == BMKT_FP_DATABASE_FULL)
974 {
975 fpi_device_enroll_complete (device,
976 NULL,
977 fpi_device_error_new (FP_DEVICE_ERROR_DATA_FULL));
978 }
979 else
980 {
981 fpi_device_enroll_complete (device,
982 NULL,
983 fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
984 "Enrollment failed (%d)",
985 resp->result));
986 }
987 break;
988 }
989
990 1 case BMKT_RSP_ENROLL_OK:
991 {
992 1 FpPrint *print = NULL;
993
994 1 fp_info ("Enrollment was successful!");
995
996 1 fpi_device_get_enroll_data (device, &print);
997
998 1 fpi_device_enroll_complete (device, g_object_ref (print), NULL);
999 1 break;
1000 }
1001 }
1002 }
1003
1004 static void
1005 1 enroll (FpDevice *device)
1006 {
1007 1 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
1008 1 FpPrint *print = NULL;
1009 1 GVariant *data = NULL;
1010 1 GVariant *uid = NULL;
1011 1 guint finger;
1012 2 g_autofree gchar *user_id = NULL;
1013 1 gssize user_id_len;
1014 1 g_autofree guint8 *payload = NULL;
1015
1016 1 fpi_device_get_enroll_data (device, &print);
1017
1018 1 G_DEBUG_HERE ();
1019
1020 1 user_id = fpi_print_generate_user_id (print);
1021
1022 1 user_id_len = strlen (user_id);
1023 1 user_id_len = MIN (BMKT_MAX_USER_ID_LEN, user_id_len);
1024
1025 /* We currently always use finger 1 from the devices point of view */
1026 1 finger = 1;
1027
1028 1 uid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
1029 user_id,
1030 user_id_len,
1031 1);
1032 1 data = g_variant_new ("(y@ay)",
1033 finger,
1034 uid);
1035
1036 1 fpi_print_set_type (print, FPI_PRINT_RAW);
1037 1 fpi_print_set_device_stored (print, TRUE);
1038 1 g_object_set (print, "fpi-data", data, NULL);
1039 1 g_object_set (print, "description", user_id, NULL);
1040
1041 1 g_debug ("user_id: %s, finger: %d", user_id, finger);
1042
1043 1 payload = g_malloc0 (user_id_len + 2);
1044
1045 /* Backup options are not supported for Prometheus */
1046 1 payload[0] = 0;
1047 1 payload[1] = finger;
1048 1 memcpy (payload + 2, user_id, user_id_len);
1049
1050 1 self->action_starting = TRUE;
1051 1 fpi_device_critical_enter (device);
1052
1053 1 synaptics_sensor_cmd (self, 0, BMKT_CMD_ENROLL_USER, payload, user_id_len + 2, enroll_msg_cb);
1054 1 }
1055
1056 static void
1057 1 delete_msg_cb (FpiDeviceSynaptics *self,
1058 bmkt_response_t *resp,
1059 GError *error)
1060 {
1061 1 FpDevice *device = FP_DEVICE (self);
1062 1 bmkt_del_user_resp_t *del_user_resp;
1063
1064
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (error)
1065 {
1066 fpi_device_critical_leave (device);
1067 fpi_device_delete_complete (device, error);
1068 return;
1069 }
1070
1071 1 del_user_resp = &resp->response.del_user_resp;
1072
1073
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (resp->response_id)
1074 {
1075 case BMKT_RSP_DELETE_PROGRESS:
1076 fp_info ("Deleting Enrolled Users is %d%% complete",
1077 del_user_resp->progress);
1078 break;
1079
1080 case BMKT_RSP_DEL_USER_FP_FAIL:
1081 fpi_device_critical_leave (device);
1082 if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS ||
1083 resp->result == BMKT_FP_DATABASE_EMPTY)
1084 {
1085 fp_info ("Database no record");
1086 fpi_device_delete_complete (device, NULL);
1087 }
1088 else
1089 {
1090 fp_info ("Failed to delete enrolled user: %d", resp->result);
1091 fpi_device_delete_complete (device,
1092 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1093 }
1094 break;
1095
1096 1 case BMKT_RSP_DEL_USER_FP_OK:
1097 1 fp_info ("Successfully deleted enrolled user");
1098 1 fpi_device_critical_leave (device);
1099 1 fpi_device_delete_complete (device, NULL);
1100 1 break;
1101 }
1102 }
1103
1104 static void
1105 1 delete_print (FpDevice *device)
1106 {
1107 1 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
1108 1 FpPrint *print = NULL;
1109
1110 1 g_autoptr(GVariant) data = NULL;
1111 1 guint8 finger;
1112 1 const guint8 *user_id;
1113 1 gsize user_id_len = 0;
1114
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 g_autofree guint8 *payload = NULL;
1115
1116 1 fpi_device_get_delete_data (device, &print);
1117
1118 1 g_object_get (print, "fpi-data", &data, NULL);
1119 1 g_debug ("data is %p", data);
1120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!parse_print_data (data, &finger, &user_id, &user_id_len))
1121 {
1122 fpi_device_delete_complete (device,
1123 fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
1124 return;
1125 }
1126
1127 1 G_DEBUG_HERE ();
1128
1129 1 payload = g_malloc0 (1 + user_id_len);
1130 1 payload[0] = finger;
1131 1 memcpy (payload + 1, user_id, user_id_len);
1132
1133 1 fpi_device_critical_enter (device);
1134 1 synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_USER_FP, payload, user_id_len + 1, delete_msg_cb);
1135 }
1136
1137 static void
1138 3 clear_storage_msg_cb (FpiDeviceSynaptics *self,
1139 bmkt_response_t *resp,
1140 GError *error)
1141 {
1142 3 FpDevice *device = FP_DEVICE (self);
1143 3 bmkt_del_all_users_resp_t *del_all_user_resp;
1144
1145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (error)
1146 {
1147 fpi_device_clear_storage_complete (device, error);
1148 return;
1149 }
1150 3 del_all_user_resp = &resp->response.del_all_user_resp;
1151
1152
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
3 switch (resp->response_id)
1153 {
1154 2 case BMKT_RSP_DELETE_PROGRESS:
1155 2 fp_info ("Deleting All Enrolled Users is %d%% complete",
1156 del_all_user_resp->progress);
1157 2 break;
1158
1159 case BMKT_RSP_DEL_FULL_DB_FAIL:
1160 if (resp->result == BMKT_FP_DATABASE_EMPTY)
1161 fpi_device_clear_storage_complete (device, NULL);
1162 else
1163 fpi_device_clear_storage_complete (device,
1164 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1165 break;
1166
1167 1 case BMKT_RSP_DEL_FULL_DB_OK:
1168 1 fp_info ("Successfully deleted all enrolled user");
1169 1 fpi_device_clear_storage_complete (device, NULL);
1170 1 break;
1171 }
1172 }
1173
1174 static void
1175 1 clear_storage (FpDevice *device)
1176 {
1177 1 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
1178
1179 1 g_debug ("clear all prints in database");
1180 1 synaptics_sensor_cmd (self, 0, BMKT_CMD_DEL_FULL_DB, NULL, 0, clear_storage_msg_cb);
1181 1 return;
1182 }
1183
1184
1185 static void
1186 1 prob_msg_cb (FpiDeviceSynaptics *self,
1187 bmkt_response_t *resp,
1188 GError *error)
1189 {
1190 1 GUsbDevice *usb_dev = NULL;
1191 1 g_autofree gchar *serial = NULL;
1192 1 GError *err = NULL;
1193
1194 1 usb_dev = fpi_device_get_usb_device (FP_DEVICE (self));
1195
1196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (error)
1197 {
1198 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1199 err = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "unsupported firmware version");
1200
1201 g_usb_device_close (usb_dev, NULL);
1202 fpi_device_probe_complete (FP_DEVICE (self), NULL, NULL, err);
1203 g_clear_error (&error);
1204 return;
1205 }
1206
1207
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
1208 1 serial = g_strdup ("emulated-device");
1209 else
1210 serial = g_usb_device_get_string_descriptor (usb_dev,
1211 g_usb_device_get_serial_number_index (usb_dev),
1212 &err);
1213
1214 /* BMKT_OPERATION_DENIED is returned if the sensor is already initialized */
1215
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (resp->result == BMKT_SUCCESS || resp->result == BMKT_OPERATION_DENIED)
1216 {
1217 1 g_usb_device_close (usb_dev, NULL);
1218 1 fpi_device_probe_complete (FP_DEVICE (self), serial, NULL, err);
1219 }
1220 else if (resp->result == BMKT_FP_SYSTEM_BUSY)
1221 {
1222 synaptics_sensor_cmd (self, self->cmd_seq_num, BMKT_CMD_CANCEL_OP, NULL, 0, NULL);
1223 }
1224 else
1225 {
1226 g_warning ("Probe fingerprint sensor failed with %d!", resp->result);
1227 g_usb_device_close (usb_dev, NULL);
1228 fpi_device_probe_complete (FP_DEVICE (self), serial, NULL, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1229 }
1230 }
1231
1232 static void
1233 1 dev_probe (FpDevice *device)
1234 {
1235 1 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
1236 1 GUsbDevice *usb_dev;
1237
1238 1 g_autoptr(FpiUsbTransfer) transfer = NULL;
1239 1 FpiByteReader reader;
1240 1 GError *error = NULL;
1241 1 guint16 status;
1242 1 const guint8 *data;
1243 1 gboolean read_ok = TRUE;
1244
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 g_autofree gchar *serial = NULL;
1245 1 gboolean retry = TRUE;
1246
1247 1 G_DEBUG_HERE ();
1248
1249 /* Claim usb interface */
1250 1 usb_dev = fpi_device_get_usb_device (device);
1251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!g_usb_device_open (usb_dev, &error))
1252 {
1253 fpi_device_probe_complete (device, NULL, NULL, error);
1254 return;
1255 }
1256
1257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!g_usb_device_claim_interface (usb_dev, 0, 0, &error))
1258 goto err_close;
1259
1260 1 while(1)
1261 {
1262 /* TODO: Do not do this synchronous. */
1263 1 transfer = fpi_usb_transfer_new (device);
1264 1 fpi_usb_transfer_fill_bulk (transfer, USB_EP_REQUEST, SENSOR_FW_CMD_HEADER_LEN);
1265 1 transfer->short_is_error = TRUE;
1266 1 transfer->buffer[0] = SENSOR_CMD_GET_VERSION;
1267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
1268 goto err_close;
1269
1270 1 g_clear_pointer (&transfer, fpi_usb_transfer_unref);
1271 1 transfer = fpi_usb_transfer_new (device);
1272 1 fpi_usb_transfer_fill_bulk (transfer, USB_EP_REPLY, 40);
1273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!fpi_usb_transfer_submit_sync (transfer, 1000, &error))
1274 goto err_close;
1275
1276 1 fpi_byte_reader_init (&reader, transfer->buffer, transfer->actual_length);
1277
1278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!fpi_byte_reader_get_uint16_le (&reader, &status))
1279 {
1280 g_warning ("Transfer in response to version query was too short");
1281 error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
1282 goto err_close;
1283 }
1284
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (status != 0)
1285 {
1286 g_warning ("Device responded with error: %d retry: %d", status, retry);
1287 if(retry)
1288 {
1289 retry = FALSE;
1290 continue;
1291 }
1292 error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
1293 goto err_close;
1294 }
1295 1 break;
1296 }
1297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_time);
1298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint32_le (&reader, &self->mis_version.build_num);
1299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_major);
1300
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.version_minor);
1301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.target);
1302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.product);
1303
1304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.silicon_rev);
1305
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.formal_release);
1306
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.platform);
1307
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.patch);
1308
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (fpi_byte_reader_get_data (&reader, sizeof (self->mis_version.serial_number), &data))
1309 1 memcpy (self->mis_version.serial_number, data, sizeof (self->mis_version.serial_number));
1310 else
1311 read_ok = FALSE;
1312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint16_le (&reader, &self->mis_version.security);
1313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.iface);
1314
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 read_ok &= fpi_byte_reader_get_uint8 (&reader, &self->mis_version.device_type);
1315
1316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!read_ok)
1317 {
1318 g_warning ("Transfer in response to version query was too short");
1319 error = fpi_device_error_new (FP_DEVICE_ERROR_PROTO);
1320 goto err_close;
1321 }
1322
1323 1 fp_dbg ("Build Time: %d", self->mis_version.build_time);
1324 1 fp_dbg ("Build Num: %d", self->mis_version.build_num);
1325 1 fp_dbg ("Version: %d.%d", self->mis_version.version_major, self->mis_version.version_minor);
1326 1 fp_dbg ("Target: %d", self->mis_version.target);
1327 1 fp_dbg ("Product: %d", self->mis_version.product);
1328
1329 1 synaptics_sensor_cmd (self, 0, BMKT_CMD_FPS_INIT, NULL, 0, prob_msg_cb);
1330
1331 1 return;
1332
1333 err_close:
1334 g_usb_device_close (usb_dev, NULL);
1335 fpi_device_probe_complete (device, NULL, NULL, error);
1336 }
1337
1338 static void
1339 1 fps_init_msg_cb (FpiDeviceSynaptics *self,
1340 bmkt_response_t *resp,
1341 GError *error)
1342 {
1343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (error)
1344 {
1345 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1346 g_clear_error (&error);
1347
1348 fpi_device_open_complete (FP_DEVICE (self), error);
1349 return;
1350 }
1351
1352 /* BMKT_OPERATION_DENIED is returned if the sensor is already initialized */
1353
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (resp->result == BMKT_SUCCESS || resp->result == BMKT_OPERATION_DENIED)
1354 {
1355 1 fpi_device_open_complete (FP_DEVICE (self), NULL);
1356 }
1357 else if (resp->result == BMKT_FP_SYSTEM_BUSY)
1358 {
1359 synaptics_sensor_cmd (self, self->cmd_seq_num, BMKT_CMD_CANCEL_OP, NULL, 0, NULL);
1360 }
1361 else
1362 {
1363 g_warning ("Initializing fingerprint sensor failed with %d!", resp->result);
1364 fpi_device_open_complete (FP_DEVICE (self),
1365 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1366 }
1367 }
1368 static void
1369 1 fps_deinit_cb (FpiDeviceSynaptics *self,
1370 bmkt_response_t *resp,
1371 GError *error)
1372 {
1373 2 g_autoptr(GError) err = NULL;
1374
1375 /* Release usb interface */
1376 1 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (self)), 0, 0, &err);
1377
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!error)
1378 1 error = g_steal_pointer (&err);
1379
1380
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_clear_object (&self->interrupt_cancellable);
1381
1382
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!error)
1383 {
1384
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 switch (resp->response_id)
1385 {
1386 1 case BMKT_RSP_POWER_DOWN_READY:
1387 1 fp_info ("Fingerprint sensor ready to be powered down");
1388 1 break;
1389
1390 case BMKT_RSP_POWER_DOWN_FAIL:
1391 fp_info ("Failed to go to power down mode: %d", resp->result);
1392 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
1393 "Power down failed: %d", resp->result);
1394
1395 break;
1396 }
1397 }
1398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 fpi_device_close_complete (FP_DEVICE (self), error);
1399 1 }
1400
1401 static void
1402 1 dev_init (FpDevice *device)
1403 {
1404 1 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
1405 1 GError *error = NULL;
1406
1407 1 G_DEBUG_HERE ();
1408
1409 1 self->interrupt_cancellable = g_cancellable_new ();
1410
1411 /* Claim usb interface */
1412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!g_usb_device_claim_interface (fpi_device_get_usb_device (device), 0, 0, &error))
1413 goto error;
1414
1415 1 synaptics_sensor_cmd (self, 0, BMKT_CMD_FPS_INIT, NULL, 0, fps_init_msg_cb);
1416
1417 1 return;
1418
1419 error:
1420 fpi_device_open_complete (FP_DEVICE (self), error);
1421 }
1422
1423 static void
1424 1 dev_exit (FpDevice *device)
1425 {
1426 1 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (device);
1427
1428 1 G_DEBUG_HERE ();
1429
1430 1 synaptics_sensor_cmd (self, 0, BMKT_CMD_POWER_DOWN_NOTIFY, NULL, 0, fps_deinit_cb);
1431 1 }
1432
1433 static void
1434 cancel (FpDevice *dev)
1435 {
1436 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
1437
1438 /* We just send out a cancel command and hope for the best. */
1439 synaptics_sensor_cmd (self, -1, BMKT_CMD_CANCEL_OP, NULL, 0, NULL);
1440
1441 /* Cancel any current interrupt transfer (resulting us to go into
1442 * response reading mode again); then create a new cancellable
1443 * for the next transfers. */
1444 g_cancellable_cancel (self->interrupt_cancellable);
1445 g_clear_object (&self->interrupt_cancellable);
1446 self->interrupt_cancellable = g_cancellable_new ();
1447 }
1448
1449 static void
1450 1 suspend (FpDevice *dev)
1451 {
1452 1 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
1453 1 FpiDeviceAction action = fpi_device_get_current_action (dev);
1454
1455 1 g_debug ("got suspend request");
1456
1457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (action != FPI_DEVICE_ACTION_VERIFY && action != FPI_DEVICE_ACTION_IDENTIFY)
1458 {
1459 fpi_device_suspend_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
1460 return;
1461 }
1462
1463 /* We are guaranteed to have a cmd_ssm running at this time. */
1464
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_assert (self->cmd_ssm);
1465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert (fpi_ssm_get_cur_state (self->cmd_ssm) == SYNAPTICS_CMD_WAIT_INTERRUPT);
1466 1 self->cmd_suspended = TRUE;
1467
1468 /* Cancel the current transfer.
1469 * The CMD SSM will go into the suspend state and signal readyness. */
1470 1 g_cancellable_cancel (self->interrupt_cancellable);
1471
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_clear_object (&self->interrupt_cancellable);
1472 1 self->interrupt_cancellable = g_cancellable_new ();
1473 }
1474
1475 static void
1476 1 resume (FpDevice *dev)
1477 {
1478 1 FpiDeviceSynaptics *self = FPI_DEVICE_SYNAPTICS (dev);
1479 1 FpiDeviceAction action = fpi_device_get_current_action (dev);
1480
1481 1 g_debug ("got resume request");
1482
1483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (action != FPI_DEVICE_ACTION_VERIFY && action != FPI_DEVICE_ACTION_IDENTIFY)
1484 {
1485 g_assert_not_reached ();
1486 fpi_device_resume_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
1487 return;
1488 }
1489
1490 /* We must have a suspended cmd_ssm at this point */
1491
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_assert (self->cmd_ssm);
1492
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert (self->cmd_suspended);
1493
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert (fpi_ssm_get_cur_state (self->cmd_ssm) == SYNAPTICS_CMD_SUSPENDED);
1494 1 self->cmd_suspended = FALSE;
1495
1496 /* Restart interrupt transfer. */
1497 1 fpi_ssm_jump_to_state (self->cmd_ssm, SYNAPTICS_CMD_RESUME);
1498
1499 1 fpi_device_resume_complete (dev, NULL);
1500 }
1501
1502 static void
1503 1 fpi_device_synaptics_init (FpiDeviceSynaptics *self)
1504 {
1505 1 }
1506
1507 static void
1508 121 fpi_device_synaptics_class_init (FpiDeviceSynapticsClass *klass)
1509 {
1510 121 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
1511
1512 121 dev_class->id = FP_COMPONENT;
1513 121 dev_class->full_name = SYNAPTICS_DRIVER_FULLNAME;
1514
1515 121 dev_class->type = FP_DEVICE_TYPE_USB;
1516 121 dev_class->scan_type = FP_SCAN_TYPE_PRESS;
1517 121 dev_class->id_table = id_table;
1518 121 dev_class->nr_enroll_stages = ENROLL_SAMPLES;
1519 121 dev_class->temp_hot_seconds = -1;
1520
1521 121 dev_class->open = dev_init;
1522 121 dev_class->close = dev_exit;
1523 121 dev_class->probe = dev_probe;
1524 121 dev_class->verify = verify;
1525 121 dev_class->identify = identify;
1526 121 dev_class->enroll = enroll;
1527 121 dev_class->delete = delete_print;
1528 121 dev_class->clear_storage = clear_storage;
1529 121 dev_class->cancel = cancel;
1530 121 dev_class->suspend = suspend;
1531 121 dev_class->resume = resume;
1532
1533 121 fpi_device_class_auto_initialize_features (dev_class);
1534 121 }
1535