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