GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 59.2% 435 / 0 / 735
Functions: 80.0% 28 / 0 / 35
Branches: 41.3% 130 / 0 / 315

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