GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 59.5% 435 / 0 / 731
Functions: 80.0% 28 / 0 / 35
Branches: 41.8% 130 / 0 / 311

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