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