GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 66.0% 566 / 0 / 858
Functions: 90.2% 37 / 0 / 41
Branches: 52.1% 170 / 0 / 326

libfprint/drivers/elanspi.c
Line Branch Exec Source
1 /*
2 * Elan SPI driver for libfprint
3 *
4 * Copyright (C) 2021 Matthew Mirvish <matthew@mm12.xyz>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #define FP_COMPONENT "elanspi"
22
23 #include "drivers_api.h"
24 #include "elanspi.h"
25
26 #include <fcntl.h>
27 #include <linux/hidraw.h>
28 #include <sys/ioctl.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <linux/types.h>
32 #include <errno.h>
33
34 struct _FpiDeviceElanSpi
35 {
36 FpImageDevice parent;
37
38 /* sensor info */
39 guint8 sensor_width, sensor_height, sensor_ic_version, sensor_id;
40 gboolean sensor_otp;
41 guint8 sensor_vcm_mode;
42
43 /* processed frame info */
44 guint8 frame_width, frame_height;
45
46 /* init info */
47 guint8 sensor_raw_version, sensor_reg_17;
48 guint8 sensor_reg_vref1, sensor_reg_28, sensor_reg_27, sensor_reg_dac2;
49
50 /* calibration info */
51 union
52 {
53 struct
54 {
55 guint8 dac_value;
56 guint8 line_ptr;
57 guint8 dacfine_retry;
58 gint64 otp_timeout;
59 } old_data;
60 struct
61 {
62 guint16 gdac_value;
63 guint16 gdac_step;
64 guint16 best_gdac;
65 guint16 best_meandiff;
66 } hv_data;
67 };
68
69 /* generic temp info for async reading */
70 guint8 sensor_status;
71 gint64 capture_timeout;
72
73 /* background / calibration parameters */
74 guint16 *bg_image;
75 guint16 *last_image;
76 guint16 *prev_frame_image;
77
78 gint fp_empty_counter;
79 GSList *fp_frame_list;
80
81 /* wait ctx */
82 gint finger_wait_debounce;
83
84 gboolean deactivating, capturing;
85
86 /* active SPI status info */
87 int spi_fd;
88 };
89
90 G_DECLARE_FINAL_TYPE (FpiDeviceElanSpi, fpi_device_elanspi, FPI, DEVICE_ELANSPI, FpImageDevice);
91
4/6
fpi_device_elanspi_class_intern_init:
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 125 times.
fpi_device_elanspi_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 (FpiDeviceElanSpi, fpi_device_elanspi, FP_TYPE_IMAGE_DEVICE);
92
93 static void
94 1 elanspi_do_hwreset (FpiDeviceElanSpi *self, GError **err)
95 {
96 /* Skip in emulation mode, since we don't mock hid devices */
97
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 20 taken 1 time.
1 if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
98 1 return;
99
100 /*
101 * TODO: Make this also work with the non-HID cases
102 */
103
104 int fd = open ((char *) fpi_device_get_udev_data (FP_DEVICE (self), FPI_DEVICE_UDEV_SUBTYPE_HIDRAW), O_RDWR);
105
106 if (fd < 0)
107 {
108 g_set_error (err, G_IO_ERROR, g_io_error_from_errno (errno), "unable to open hid");
109 return;
110 }
111
112 guint8 buf[5] = {
113 0xe, 0, 0, 0, 0
114 };
115
116 if (ioctl (fd, HIDIOCSFEATURE (5), &buf) != 5)
117 {
118 g_set_error (err, G_IO_ERROR, g_io_error_from_errno (errno), "unable to reset via hid");
119 goto out;
120 }
121
122 out:
123 close (fd);
124 }
125
126 /*
127 * Three main processes involved in driving these sensors:
128 * - initialization (device type detection)
129 * - calibration
130 * - image capture (single)
131 * - image capture (stitched)
132 */
133
134 enum elanspi_init_state {
135 ELANSPI_INIT_READ_STATUS1,
136 ELANSPI_INIT_HWSWRESET, /* fused b.c. hw reset is currently sync */
137 ELANSPI_INIT_SWRESETDELAY1,
138 ELANSPI_INIT_READ_HEIGHT,
139 ELANSPI_INIT_READ_WIDTH,
140 ELANSPI_INIT_READ_REG17, /* both of these states finish setting up sensor settings */
141 ELANSPI_INIT_READ_VERSION, /* can jump straight to calibrate */
142 ELANSPI_INIT_SWRESET2,
143 ELANSPI_INIT_SWRESETDELAY2,
144 ELANSPI_INIT_OTP_READ_VREF1,
145 ELANSPI_INIT_OTP_WRITE_VREF1,
146 ELANSPI_INIT_OTP_WRITE_0x28,
147 ELANSPI_INIT_OTP_LOOP_READ_0x28, /* may loop */
148 ELANSPI_INIT_OTP_LOOP_READ_0x27,
149 ELANSPI_INIT_OTP_LOOP_UPDATEDAC_READ_DAC2,
150 ELANSPI_INIT_OTP_LOOP_UPDATEDAC_WRITE_DAC2,
151 ELANSPI_INIT_OTP_LOOP_UPDATEDAC_WRITE_10,
152 /* exit loop */
153 ELANSPI_INIT_OTP_WRITE_0xb,
154 ELANSPI_INIT_OTP_WRITE_0xc,
155 /* do calibration (mutexc) */
156 ELANSPI_INIT_CALIBRATE,
157 ELANSPI_INIT_BG_CAPTURE,
158 ELANSPI_INIT_BG_SAVE,
159 ELANSPI_INIT_NSTATES
160 };
161
162 enum elanspi_calibrate_old_state {
163 ELANSPI_CALIBOLD_UNPROTECT,
164 ELANSPI_CALIBOLD_WRITE_STARTCALIB,
165 ELANSPI_CALIBOLD_STARTCALIBDELAY,
166 ELANSPI_CALIBOLD_SEND_REGTABLE,
167 /* calibrate dac base value */
168 ELANSPI_CALIBOLD_DACBASE_CAPTURE,
169 ELANSPI_CALIBOLD_DACBASE_WRITE_DAC1,
170 /* check for finger */
171 ELANSPI_CALIBOLD_CHECKFIN_CAPTURE,
172 /* increase gain */
173 ELANSPI_CALIBOLD_WRITE_GAIN,
174 /* calibrate dac stage2 */
175 ELANSPI_CALIBOLD_DACFINE_CAPTURE,
176 ELANSPI_CALIBOLD_DACFINE_WRITE_DAC1,
177 ELANSPI_CALIBOLD_DACFINE_LOOP,
178 /* exit ok (cleanup by protecting) */
179 ELANSPI_CALIBOLD_PROTECT,
180 ELANSPI_CALIBOLD_NSTATES
181 };
182
183 enum elanspi_capture_old_state {
184 ELANSPI_CAPTOLD_WRITE_CAPTURE,
185 ELANSPI_CAPTOLD_CHECK_LINEREADY,
186 ELANSPI_CAPTOLD_RECV_LINE,
187
188 ELANSPI_CAPTOLD_NSTATES
189 };
190
191 enum elanspi_calibrate_hv_state {
192 ELANSPI_CALIBHV_SELECT_PAGE0_0,
193 ELANSPI_CALIBHV_WRITE_STARTCALIB,
194 ELANSPI_CALIBHV_UNPROTECT,
195 ELANSPI_CALIBHV_SEND_REGTABLE0,
196 ELANSPI_CALIBHV_SELECT_PAGE1,
197 ELANSPI_CALIBHV_SEND_REGTABLE1,
198 ELANSPI_CALIBHV_SELECT_PAGE0_1,
199 ELANSPI_CALIBHV_WRITE_GDAC_H,
200 ELANSPI_CALIBHV_WRITE_GDAC_L,
201 ELANSPI_CALIBHV_CAPTURE,
202 ELANSPI_CALIBHV_PROCESS,
203 ELANSPI_CALIBHV_WRITE_BEST_GDAC_H,
204 ELANSPI_CALIBHV_WRITE_BEST_GDAC_L,
205 /* cleanup by protecting */
206 ELANSPI_CALIBHV_PROTECT,
207 ELANSPI_CALIBHV_NSTATES
208 };
209
210 enum elanspi_capture_hv_state {
211 ELANSPI_CAPTHV_WRITE_CAPTURE,
212 ELANSPI_CAPTHV_CHECK_READY,
213 ELANSPI_CAPTHV_RECV_IMAGE,
214 ELANSPI_CAPTHV_NSTATES
215 };
216
217 enum elanspi_write_regtable_state {
218 ELANSPI_WRTABLE_WRITE,
219 ELANSPI_WRTABLE_ITERATE,
220 ELANSPI_WRTABLE_NSTATES
221 };
222
223 enum elanspi_fp_capture_state {
224 ELANSPI_FPCAPT_INIT,
225 /* wait for finger */
226 ELANSPI_FPCAPT_WAITDOWN_CAPTURE,
227 ELANSPI_FPCAPT_WAITDOWN_PROCESS,
228 /* capture full image */
229 ELANSPI_FPCAPT_FP_CAPTURE,
230 ELANSPI_FPCAPT_FP_PROCESS,
231 /* wait for no finger */
232 ELANSPI_FPCAPT_WAITUP_CAPTURE,
233 ELANSPI_FPCAPT_WAITUP_PROCESS,
234 ELANSPI_FPCAPT_NSTATES
235 };
236
237 /* helpers */
238
239 static FpiSpiTransfer *
240 2 elanspi_do_swreset (FpiDeviceElanSpi *self)
241 {
242 2 FpiSpiTransfer * xfer = fpi_spi_transfer_new (FP_DEVICE (self), self->spi_fd);
243
244 2 fpi_spi_transfer_write (xfer, 1);
245 2 xfer->buffer_wr[0] = 0x31;
246 2 return xfer;
247 }
248 static FpiSpiTransfer *
249 1 elanspi_do_startcalib (FpiDeviceElanSpi *self)
250 {
251 1 FpiSpiTransfer * xfer = fpi_spi_transfer_new (FP_DEVICE (self), self->spi_fd);
252
253 1 fpi_spi_transfer_write (xfer, 1);
254 1 xfer->buffer_wr[0] = 0x4;
255 1 return xfer;
256 }
257 static FpiSpiTransfer *
258 77 elanspi_do_capture (FpiDeviceElanSpi *self)
259 {
260 77 FpiSpiTransfer * xfer = fpi_spi_transfer_new (FP_DEVICE (self), self->spi_fd);
261
262 77 fpi_spi_transfer_write (xfer, 1);
263 77 xfer->buffer_wr[0] = 0x1;
264 77 return xfer;
265 }
266 static FpiSpiTransfer *
267 elanspi_do_selectpage (FpiDeviceElanSpi *self, guint8 page)
268 {
269 FpiSpiTransfer * xfer = fpi_spi_transfer_new (FP_DEVICE (self), self->spi_fd);
270
271 fpi_spi_transfer_write (xfer, 2);
272 xfer->buffer_wr[0] = 0x7;
273 xfer->buffer_wr[1] = page;
274 return xfer;
275 }
276
277 static FpiSpiTransfer *
278 7995 elanspi_single_read_cmd (FpiDeviceElanSpi *self, guint8 cmd_id, guint8 *data_out)
279 {
280 7995 FpiSpiTransfer * xfer = fpi_spi_transfer_new (FP_DEVICE (self), self->spi_fd);
281
282 7995 fpi_spi_transfer_write (xfer, 2);
283 7995 xfer->buffer_wr[0] = cmd_id;
284 7995 xfer->buffer_wr[1] = 0xff;
285 7995 fpi_spi_transfer_read_full (xfer, data_out, 1, NULL);
286 7995 return xfer;
287 }
288
289 static FpiSpiTransfer *
290 7992 elanspi_read_status (FpiDeviceElanSpi *self, guint8 *data_out)
291 {
292 7992 return elanspi_single_read_cmd (self, 0x3, data_out);
293 }
294 static FpiSpiTransfer *
295 1 elanspi_read_width (FpiDeviceElanSpi *self, guint8 *data_out)
296 {
297 1 return elanspi_single_read_cmd (self, 0x9, data_out);
298 }
299 static FpiSpiTransfer *
300 1 elanspi_read_height (FpiDeviceElanSpi *self, guint8 *data_out)
301 {
302 1 return elanspi_single_read_cmd (self, 0x8, data_out);
303 }
304 static FpiSpiTransfer *
305 1 elanspi_read_version (FpiDeviceElanSpi *self, guint8 *data_out)
306 {
307 1 return elanspi_single_read_cmd (self, 0xa, data_out);
308 }
309
310 static FpiSpiTransfer *
311 4 elanspi_read_register (FpiDeviceElanSpi *self, guint8 reg_id, guint8 *data_out)
312 {
313 4 FpiSpiTransfer * xfer = fpi_spi_transfer_new (FP_DEVICE (self), self->spi_fd);
314
315 4 fpi_spi_transfer_write (xfer, 1);
316 4 xfer->buffer_wr[0] = reg_id | 0x40;
317 4 fpi_spi_transfer_read_full (xfer, data_out, 1, NULL);
318 4 return xfer;
319 }
320
321 static FpiSpiTransfer *
322 33 elanspi_write_register (FpiDeviceElanSpi *self, guint8 reg_id, guint8 data_in)
323 {
324 33 FpiSpiTransfer * xfer = fpi_spi_transfer_new (FP_DEVICE (self), self->spi_fd);
325
326 33 fpi_spi_transfer_write (xfer, 2);
327 33 xfer->buffer_wr[0] = reg_id | 0x80;
328 33 xfer->buffer_wr[1] = data_in;
329 33 return xfer;
330 }
331
332 static void
333 1 elanspi_determine_sensor (FpiDeviceElanSpi *self, GError **err)
334 {
335 1 guint8 raw_height = self->sensor_height;
336 1 guint8 raw_width = self->sensor_width;
337
338
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 5 not taken.
1 if (((raw_height == 0xa1) && (raw_width == 0xa1)) ||
339
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 5 not taken.
1 ((raw_height == 0xd1) && (raw_width == 0x51)) ||
340
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1 time.
1 ((raw_height == 0xc1) && (raw_width == 0x39)))
341 {
342 self->sensor_ic_version = 0; /* Version 0 */
343 self->sensor_width = raw_width - 1;
344 self->sensor_height = raw_height - 1;
345 }
346 else
347 {
348 /* If the sensor is exactly 96x96 (0x60 x 0x60), the version is the high bit of register 17 */
349
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 8 not taken.
1 if (raw_width == 0x60 && raw_height == 0x60)
350 {
351 1 self->sensor_ic_version = (self->sensor_reg_17 & 0x80) ? 1 : 0;
352 }
353 else
354 {
355 if (((raw_height != 0xa0) || (raw_width != 0x50)) &&
356 ((raw_height != 0x90) || (raw_width != 0x40)) &&
357 ((raw_height != 0x78) || (raw_width != 0x78)))
358 {
359 if (((raw_height != 0x40) || (raw_width != 0x58)) &&
360 ((raw_height != 0x50) || (raw_width != 0x50)))
361 {
362 /* Old sensor hack?? */
363 self->sensor_width = 0x78;
364 self->sensor_height = 0x78;
365 self->sensor_ic_version = 0;
366 }
367 else
368 {
369 /* Otherwise, read the version 'normally' */
370 self->sensor_ic_version = (self->sensor_raw_version & 0x70) >> 4;
371 }
372 }
373 else
374 {
375 self->sensor_ic_version = 1;
376 }
377 }
378 }
379
380 1 fp_dbg ("<init/detect> after hardcoded lookup; %dx%d, version %d", self->sensor_width, self->sensor_height, self->sensor_ic_version);
381
382
1/2
✓ Branch 24 → 18 taken 7 times.
✗ Branch 24 → 25 not taken.
8 for (const struct elanspi_sensor_entry *entry = elanspi_sensor_table; entry->name; entry += 1)
383 {
384
5/6
✓ Branch 18 → 19 taken 2 times.
✓ Branch 18 → 23 taken 5 times.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 23 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
✗ Branch 20 → 23 not taken.
7 if (entry->ic_version == self->sensor_ic_version && entry->width == self->sensor_width && entry->height == self->sensor_height)
385 {
386 1 self->sensor_id = entry->sensor_id;
387 1 self->sensor_otp = entry->is_otp_model;
388
389 1 fp_dbg ("<init/detect> found sensor ID %d => [%s] (%d x %d)", self->sensor_id, entry->name, self->sensor_width, self->sensor_height);
390 1 break;
391 }
392 }
393
394
1/2
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 28 taken 1 time.
1 if (self->sensor_id == 0xff)
395 {
396 *err = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, "unknown sensor (%dx%d, v%d)", self->sensor_width, self->sensor_height, self->sensor_ic_version);
397 return;
398 }
399
400 /* setup frame size */
401
1/2
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 1 time.
1 if (fpi_device_get_driver_data (FP_DEVICE (self)) & ELANSPI_HV_FLIPPED)
402 {
403 self->frame_width = self->sensor_height;
404 self->frame_height = self->sensor_width > ELANSPI_MAX_FRAME_HEIGHT ? ELANSPI_MAX_FRAME_HEIGHT : self->sensor_width;
405 }
406 else
407 {
408 1 self->frame_width = self->sensor_width;
409 1 self->frame_height = self->sensor_height > ELANSPI_MAX_FRAME_HEIGHT ? ELANSPI_MAX_FRAME_HEIGHT : self->sensor_height;
410 }
411 }
412
413 static void
414 7392 elanspi_capture_old_line_handler (FpiSpiTransfer *transfer, FpDevice *dev, gpointer unused_data, GError *error)
415 {
416 7392 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
417
418
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 7392 times.
7392 if (error)
419 {
420 fpi_ssm_mark_failed (transfer->ssm, error);
421 return;
422 }
423
424 /* copy buffer from line into last_image */
425
2/2
✓ Branch 6 → 5 taken 709632 times.
✓ Branch 6 → 7 taken 7392 times.
717024 for (int col = 0; col < self->sensor_width; col += 1)
426 {
427 709632 guint8 low = transfer->buffer_rd[col * 2 + 1];
428 709632 guint8 high = transfer->buffer_rd[col * 2];
429
430 709632 self->last_image[self->sensor_width * self->old_data.line_ptr + col] = low + high * 0x100;
431 }
432
433 /* increment line ptr */
434 7392 self->old_data.line_ptr += 1;
435 /* if there is still data, continue from check lineready */
436
2/2
✓ Branch 7 → 8 taken 7315 times.
✓ Branch 7 → 9 taken 77 times.
7392 if (self->old_data.line_ptr < self->sensor_height)
437 {
438 7315 fpi_ssm_jump_to_state (transfer->ssm, ELANSPI_CAPTOLD_CHECK_LINEREADY);
439 }
440 else
441 {
442 /* check for termination */
443
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 13 taken 77 times.
77 if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_NONE)
444 {
445 fpi_ssm_mark_completed (transfer->ssm);
446 return;
447 }
448 /* check for cancellation */
449
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 19 taken 77 times.
77 if (fpi_device_action_is_cancelled (dev))
450 {
451 g_cancellable_set_error_if_cancelled (fpi_device_get_cancellable (dev), &error);
452 fpi_ssm_mark_failed (transfer->ssm, error);
453 return;
454 }
455 /* otherwise finish succesfully */
456 77 fpi_ssm_mark_completed (transfer->ssm);
457 }
458 }
459
460 static void
461 16059 elanspi_capture_old_handler (FpiSsm *ssm, FpDevice *dev)
462 {
463 16059 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
464 16059 FpiSpiTransfer *xfer = NULL;
465
466
3/4
✓ Branch 3 → 4 taken 77 times.
✓ Branch 3 → 8 taken 7991 times.
✓ Branch 3 → 11 taken 7991 times.
✗ Branch 3 → 27 not taken.
16059 switch (fpi_ssm_get_cur_state (ssm))
467 {
468 77 case ELANSPI_CAPTOLD_WRITE_CAPTURE:
469 /* reset capture state */
470 77 self->old_data.line_ptr = 0;
471 77 self->capture_timeout = g_get_monotonic_time () + ELANSPI_OLD_CAPTURE_TIMEOUT_USEC;
472 77 xfer = elanspi_do_capture (self);
473 77 xfer->ssm = ssm;
474 77 fpi_spi_transfer_submit (xfer, NULL, fpi_ssm_spi_transfer_cb, NULL);
475 77 return;
476
477 7991 case ELANSPI_CAPTOLD_CHECK_LINEREADY:
478 7991 xfer = elanspi_read_status (self, &self->sensor_status);
479 7991 xfer->ssm = ssm;
480 7991 fpi_spi_transfer_submit (xfer, NULL, fpi_ssm_spi_transfer_cb, NULL);
481 7991 return;
482
483 7991 case ELANSPI_CAPTOLD_RECV_LINE:
484 /* is the sensor ready? */
485
2/2
✓ Branch 11 → 12 taken 599 times.
✓ Branch 11 → 22 taken 7392 times.
7991 if (!(self->sensor_status & 4))
486 {
487 /* has the timeout expired? -- disabled in testing since valgrind is very slow */
488
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 20 taken 599 times.
599 if (g_get_monotonic_time () > self->capture_timeout &&
489 !fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
490 {
491 /* end with a timeout */
492 fpi_ssm_mark_failed (ssm, g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "timed out waiting for new line"));
493 return;
494 }
495 /* check again */
496 599 fpi_ssm_jump_to_state (ssm, ELANSPI_CAPTOLD_CHECK_LINEREADY);
497 599 return;
498 }
499 /* otherwise, perform a read */
500 7392 xfer = fpi_spi_transfer_new (dev, self->spi_fd);
501 7392 xfer->ssm = ssm;
502 7392 fpi_spi_transfer_write (xfer, 2);
503 7392 xfer->buffer_wr[0] = 0x10; /* receieve line */
504 7392 fpi_spi_transfer_read (xfer, self->sensor_width * 2);
505 7392 fpi_spi_transfer_submit (xfer, NULL, elanspi_capture_old_line_handler, NULL);
506 7392 return;
507 }
508 }
509
510 static void
511 50 elanspi_send_regtable_handler (FpiSsm *ssm, FpDevice *dev)
512 {
513 50 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
514 50 FpiSpiTransfer *xfer = NULL;
515 50 const struct elanspi_reg_entry *entry = fpi_ssm_get_data (ssm);
516
517
2/3
✓ Branch 4 → 5 taken 25 times.
✓ Branch 4 → 9 taken 25 times.
✗ Branch 4 → 15 not taken.
50 switch (fpi_ssm_get_cur_state (ssm))
518 {
519 25 case ELANSPI_WRTABLE_WRITE:
520 25 xfer = elanspi_write_register (self, entry->addr, entry->value);
521 25 xfer->ssm = ssm;
522 25 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
523 25 return;
524
525 25 case ELANSPI_WRTABLE_ITERATE:
526 25 entry += 1;
527
2/2
✓ Branch 9 → 10 taken 24 times.
✓ Branch 9 → 13 taken 1 time.
25 if (entry->addr != 0xff)
528 {
529 24 fpi_ssm_set_data (ssm, (gpointer) entry, NULL);
530 24 fpi_ssm_jump_to_state (ssm, ELANSPI_WRTABLE_WRITE);
531 24 return;
532 }
533 1 fpi_ssm_mark_completed (ssm);
534 1 return;
535 }
536 }
537
538 static FpiSsm *
539 1 elanspi_write_regtable (FpiDeviceElanSpi *self, const struct elanspi_regtable * table)
540 {
541 /* find regtable pointer */
542 1 const struct elanspi_reg_entry * starting_entry = table->other;
543
544
1/2
✓ Branch 5 → 3 taken 3 times.
✗ Branch 5 → 6 not taken.
3 for (int i = 0; table->entries[i].table; i += 1)
545 {
546
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 6 taken 1 time.
3 if (table->entries[i].sid == self->sensor_id)
547 {
548 starting_entry = table->entries[i].table;
549 break;
550 }
551 }
552
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 9 taken 1 time.
1 if (starting_entry == NULL)
553 {
554 fp_err ("<regtable> unknown regtable for sensor %d", self->sensor_id);
555 return NULL;
556 }
557
558 1 FpiSsm * ssm = fpi_ssm_new (FP_DEVICE (self), elanspi_send_regtable_handler, ELANSPI_WRTABLE_NSTATES);
559
560 1 fpi_ssm_set_data (ssm, (gpointer) starting_entry, NULL);
561 1 return ssm;
562 }
563
564 static int
565 3 elanspi_mean_image (FpiDeviceElanSpi *self, const guint16 *img)
566 {
567 3 int total = 0;
568
569
6/10
✓ Branch 27 → 26 taken 9216 times.
✓ Branch 27 → 28 taken 1 time.
✓ Branch 37 → 36 taken 9216 times.
✓ Branch 37 → 38 taken 1 time.
✓ Branch 48 → 47 taken 9216 times.
✓ Branch 48 → 49 taken 1 time.
✗ Branch 52 → 51 not taken.
✗ Branch 52 → 53 not taken.
✗ Branch 64 → 63 not taken.
✗ Branch 64 → 65 not taken.
27651 for (int i = 0; i < self->sensor_width * self->sensor_height; i += 1)
570 27648 total += img[i];
571 3 return total / (self->sensor_width * self->sensor_height);
572 }
573
574 static void
575 11 elanspi_calibrate_old_handler (FpiSsm *ssm, FpDevice *dev)
576 {
577 11 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
578 11 FpiSpiTransfer *xfer = NULL;
579 11 GError *err = NULL;
580 11 FpiSsm *chld = NULL;
581 11 int mean_value = 0;
582
583
9/11
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 8 taken 1 time.
✓ Branch 3 → 12 taken 1 time.
✓ Branch 3 → 14 taken 1 time.
✓ Branch 3 → 21 taken 3 times.
✓ Branch 3 → 25 taken 1 time.
✓ Branch 3 → 35 taken 1 time.
✓ Branch 3 → 46 taken 1 time.
✗ Branch 3 → 59 not taken.
✓ Branch 3 → 66 taken 1 time.
✗ Branch 3 → 71 not taken.
11 switch (fpi_ssm_get_cur_state (ssm))
584 {
585 1 case ELANSPI_CALIBOLD_UNPROTECT:
586 1 xfer = elanspi_write_register (self, 0x00, 0x5a);
587 1 xfer->ssm = ssm;
588 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
589 1 return;
590
591 1 case ELANSPI_CALIBOLD_WRITE_STARTCALIB:
592 1 xfer = elanspi_do_startcalib (self);
593 1 xfer->ssm = ssm;
594 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
595 1 return;
596
597 1 case ELANSPI_CALIBOLD_STARTCALIBDELAY:
598 1 fpi_ssm_next_state_delayed (ssm, 1);
599 1 return;
600
601 1 case ELANSPI_CALIBOLD_SEND_REGTABLE:
602 1 chld = elanspi_write_regtable (self, &elanspi_calibration_table_old);
603
1/2
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 19 taken 1 time.
1 if (chld == NULL)
604 {
605 err = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, "unknown calibration table for sensor");
606 fpi_ssm_mark_failed (ssm, err);
607 return;
608 }
609 1 fpi_ssm_start_subsm (ssm, chld);
610 1 return;
611
612 3 case ELANSPI_CALIBOLD_DACBASE_CAPTURE:
613 case ELANSPI_CALIBOLD_CHECKFIN_CAPTURE:
614 case ELANSPI_CALIBOLD_DACFINE_CAPTURE:
615 3 chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES);
616 3 fpi_ssm_silence_debug (chld);
617 3 fpi_ssm_start_subsm (ssm, chld);
618 3 return;
619
620 1 case ELANSPI_CALIBOLD_DACBASE_WRITE_DAC1:
621 /* compute dac */
622 1 self->old_data.dac_value = ((elanspi_mean_image (self, self->last_image) & 0xffff) + 0x80) >> 8;
623
1/2
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 1 time.
1 if (0x3f < self->old_data.dac_value)
624 self->old_data.dac_value = 0x3f;
625 1 fp_dbg ("<calibold> dac init is 0x%02x", self->old_data.dac_value);
626 /* write it */
627 1 xfer = elanspi_write_register (self, 0x6, self->old_data.dac_value - 0x40);
628 1 xfer->ssm = ssm;
629 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
630 1 return;
631
632 1 case ELANSPI_CALIBOLD_WRITE_GAIN:
633 /* check if finger was present */
634
1/2
✗ Branch 38 → 39 not taken.
✓ Branch 38 → 42 taken 1 time.
2 if (elanspi_mean_image (self, self->last_image) >= ELANSPI_MAX_OLD_STAGE1_CALIBRATION_MEAN)
635 {
636 err = fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER, "finger on sensor during calibration");
637 fpi_ssm_mark_failed (ssm, err);
638 return;
639 }
640 /* if ok, increase gain */
641 1 xfer = elanspi_write_register (self, 0x5, 0x6f);
642 1 xfer->ssm = ssm;
643 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
644 /* initialize retry counter */
645 1 self->old_data.dacfine_retry = 0;
646 1 return;
647
648 1 case ELANSPI_CALIBOLD_DACFINE_WRITE_DAC1:
649 1 mean_value = elanspi_mean_image (self, self->last_image);
650
1/2
✓ Branch 49 → 50 taken 1 time.
✗ Branch 49 → 52 not taken.
1 if (mean_value >= ELANSPI_MIN_OLD_STAGE2_CALBIRATION_MEAN && mean_value <= ELANSPI_MAX_OLD_STAGE2_CALBIRATION_MEAN)
651 {
652 /* finished calibration, goto bg */
653 1 fpi_ssm_jump_to_state (ssm, ELANSPI_CALIBOLD_PROTECT);
654 1 return;
655 }
656
657 if (mean_value < (ELANSPI_MIN_OLD_STAGE2_CALBIRATION_MEAN + (ELANSPI_MAX_OLD_STAGE2_CALBIRATION_MEAN - ELANSPI_MIN_OLD_STAGE2_CALBIRATION_MEAN) / 2))
658 self->old_data.dac_value -= 1;
659 else
660 self->old_data.dac_value += 1;
661
662 /* write it */
663 xfer = elanspi_write_register (self, 0x6, self->old_data.dac_value - 0x40);
664 xfer->ssm = ssm;
665 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
666 return;
667
668 case ELANSPI_CALIBOLD_DACFINE_LOOP:
669 /* check the retry counter */
670 self->old_data.dacfine_retry += 1;
671 if (self->old_data.dacfine_retry >= 2)
672 {
673 /* bail with calibration error */
674 err = fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER, "finger on sensor during calibration");
675 fpi_ssm_mark_failed (ssm, err);
676 return;
677 }
678 fp_dbg ("<calibold> repeating calibration for the %dth time", self->old_data.dacfine_retry);
679 /* otherwise, take another image */
680 fpi_ssm_jump_to_state (ssm, ELANSPI_CALIBOLD_DACFINE_CAPTURE);
681 return;
682
683 1 case ELANSPI_CALIBOLD_PROTECT:
684 1 fp_dbg ("<calibold> calibration ok, saving bg image");
685 1 xfer = elanspi_write_register (self, 0x00, 0x00);
686 1 xfer->ssm = ssm;
687 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
688 1 return;
689 }
690 }
691
692 static void
693 elanspi_capture_hv_image_handler (FpiSpiTransfer *transfer, FpDevice *dev, gpointer unused_data, GError *error)
694 {
695 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
696
697 if (error)
698 {
699 fpi_ssm_mark_failed (transfer->ssm, error);
700 return;
701 }
702
703 int i, outptr;
704 guint16 value = 0;
705
706 for (i = 0, outptr = 0; i < transfer->length_rd && outptr < (self->sensor_height * self->sensor_width * 2); i += 1)
707 {
708 if (transfer->buffer_rd[i] != 0xff)
709 {
710 if (outptr % 2)
711 {
712 value <<= 8;
713 value |= transfer->buffer_rd[i];
714 self->last_image[outptr / 2] = value;
715 }
716 else
717 {
718 value = transfer->buffer_rd[i];
719 }
720 outptr += 1;
721 }
722 }
723
724 if (outptr != (self->sensor_height * self->sensor_width * 2))
725 {
726 fp_warn ("<capture/hv> did not receive full image");
727 /* mark ssm failed */
728 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "hv image receieve did not fill buffer");
729 fpi_ssm_mark_failed (transfer->ssm, error);
730 return;
731 }
732
733 fpi_ssm_mark_completed (transfer->ssm);
734 }
735
736
737 static void
738 elanspi_capture_hv_handler (FpiSsm *ssm, FpDevice *dev)
739 {
740 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
741 FpiSpiTransfer *xfer = NULL;
742
743 switch (fpi_ssm_get_cur_state (ssm))
744 {
745 case ELANSPI_CAPTHV_WRITE_CAPTURE:
746 /* reset capture state */
747 self->old_data.line_ptr = 0;
748 self->capture_timeout = g_get_monotonic_time () + ELANSPI_HV_CAPTURE_TIMEOUT_USEC;
749 xfer = elanspi_do_capture (self);
750 xfer->ssm = ssm;
751 /* these are specifically cancellable because they don't leave the device at some aribtrary line offset, since
752 * these devices only send entire images */
753 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
754 return;
755
756 case ELANSPI_CAPTHV_CHECK_READY:
757 xfer = elanspi_read_status (self, &self->sensor_status);
758 xfer->ssm = ssm;
759 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
760 return;
761
762 case ELANSPI_CAPTHV_RECV_IMAGE:
763 /* is the sensor ready? */
764 if (!(self->sensor_status & 4))
765 {
766 /* has the timeout expired? */
767 if (g_get_monotonic_time () > self->capture_timeout)
768 {
769 /* end with a timeout */
770 fpi_ssm_mark_failed (ssm, g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "timed out waiting for image"));
771 return;
772 }
773 /* check again */
774 fpi_ssm_jump_to_state (ssm, ELANSPI_CAPTHV_CHECK_READY);
775 return;
776 }
777 /* otherwise, read the image
778 * the hv sensors seem to use 128 bytes of padding(?) this is only tested on the 0xe sensors */
779 xfer = fpi_spi_transfer_new (dev, self->spi_fd);
780 xfer->ssm = ssm;
781 fpi_spi_transfer_write (xfer, 2);
782 xfer->buffer_wr[0] = 0x10; /* receieve line */
783 fpi_spi_transfer_read (xfer, self->sensor_height * (self->sensor_width * 2 + 48));
784 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), elanspi_capture_hv_image_handler, NULL);
785 return;
786 }
787 }
788
789 static void
790 elanspi_calibrate_hv_handler (FpiSsm *ssm, FpDevice *dev)
791 {
792 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
793 FpiSpiTransfer *xfer = NULL;
794 GError *err = NULL;
795 FpiSsm *chld = NULL;
796 int mean_diff = 0;
797
798 switch (fpi_ssm_get_cur_state (ssm))
799 {
800 case ELANSPI_CALIBHV_SELECT_PAGE0_0:
801 /* initialize gdac */
802 self->hv_data.gdac_value = 0x100;
803 self->hv_data.gdac_step = 0x100;
804 self->hv_data.best_gdac = 0x0;
805 self->hv_data.best_meandiff = 0xffff;
806
807 case ELANSPI_CALIBHV_SELECT_PAGE0_1:
808 xfer = elanspi_do_selectpage (self, 0);
809 xfer->ssm = ssm;
810 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
811 return;
812
813 case ELANSPI_CALIBHV_WRITE_STARTCALIB:
814 xfer = elanspi_do_startcalib (self);
815 xfer->ssm = ssm;
816 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
817 return;
818
819 case ELANSPI_CALIBHV_UNPROTECT:
820 xfer = elanspi_write_register (self, 0x00, 0x5a);
821 xfer->ssm = ssm;
822 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
823 return;
824
825 case ELANSPI_CALIBHV_SEND_REGTABLE0:
826 chld = elanspi_write_regtable (self, &elanspi_calibration_table_new_page0);
827 if (chld == NULL)
828 {
829 err = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, "unknown calibration table for sensor");
830 fpi_ssm_mark_failed (ssm, err);
831 return;
832 }
833 fpi_ssm_start_subsm (ssm, chld);
834 return;
835
836 case ELANSPI_CALIBHV_SELECT_PAGE1:
837 xfer = elanspi_do_selectpage (self, 1);
838 xfer->ssm = ssm;
839 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
840 return;
841
842 case ELANSPI_CALIBHV_SEND_REGTABLE1:
843 chld = elanspi_write_regtable (self, &elanspi_calibration_table_new_page1);
844 if (chld == NULL)
845 {
846 err = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, "unknown calibration table for sensor");
847 fpi_ssm_mark_failed (ssm, err);
848 return;
849 }
850 fpi_ssm_start_subsm (ssm, chld);
851 return;
852
853 case ELANSPI_CALIBHV_WRITE_GDAC_H:
854 case ELANSPI_CALIBHV_WRITE_BEST_GDAC_H:
855 if (fpi_ssm_get_cur_state (ssm) == ELANSPI_CALIBHV_WRITE_BEST_GDAC_H)
856 self->hv_data.gdac_value = self->hv_data.best_gdac;
857 xfer = elanspi_write_register (self, 0x06, (self->hv_data.gdac_value >> 2) & 0xff);
858 xfer->ssm = ssm;
859 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
860 return;
861
862 case ELANSPI_CALIBHV_WRITE_GDAC_L:
863 case ELANSPI_CALIBHV_WRITE_BEST_GDAC_L:
864 xfer = elanspi_write_register (self, 0x07, self->hv_data.gdac_value & 3);
865 xfer->ssm = ssm;
866 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
867 return;
868
869 case ELANSPI_CALIBHV_CAPTURE:
870 chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES);
871 fpi_ssm_silence_debug (chld);
872 fpi_ssm_start_subsm (ssm, chld);
873 return;
874
875 case ELANSPI_CALIBHV_PROCESS:
876 /* compute mean */
877 mean_diff = abs (elanspi_mean_image (self, self->last_image) - ELANSPI_HV_CALIBRATION_TARGET_MEAN);
878 if (mean_diff < 100)
879 {
880 fp_dbg ("<calibhv> calibration ok (mdiff < 100 w/ gdac=%04x)", self->hv_data.gdac_value);
881 /* exit early, jump right to protect */
882 fpi_ssm_jump_to_state (ssm, ELANSPI_CALIBHV_PROTECT);
883 return;
884 }
885 if (mean_diff < self->hv_data.best_meandiff)
886 {
887 self->hv_data.best_meandiff = mean_diff;
888 self->hv_data.best_gdac = self->hv_data.gdac_value;
889 }
890 /* shrink step */
891 self->hv_data.gdac_step /= 2;
892 if (self->hv_data.gdac_step == 0)
893 {
894 fp_dbg ("<calibhv> calibration ok (step = 0 w/ best_gdac=%04x)", self->hv_data.best_gdac);
895 /* exit, using best value */
896 fpi_ssm_jump_to_state (ssm, ELANSPI_CALIBHV_WRITE_BEST_GDAC_H);
897 return;
898 }
899 /* update gdac */
900 if (elanspi_mean_image (self, self->last_image) < ELANSPI_HV_CALIBRATION_TARGET_MEAN)
901 self->hv_data.gdac_value -= self->hv_data.gdac_step;
902 else
903 self->hv_data.gdac_value += self->hv_data.gdac_step;
904 /* advance back to capture */
905 fpi_ssm_jump_to_state (ssm, ELANSPI_CALIBHV_WRITE_GDAC_H);
906 return;
907
908 case ELANSPI_CALIBHV_PROTECT:
909 fp_dbg ("<calibhv> calibration ok, saving bg image");
910 xfer = elanspi_write_register (self, 0x00, 0x00);
911 xfer->ssm = ssm;
912 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
913 return;
914
915 }
916 }
917
918 static void
919 20 elanspi_init_ssm_handler (FpiSsm *ssm, FpDevice *dev)
920 {
921 20 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
922 20 FpiSpiTransfer *xfer = NULL;
923 20 GError *err = NULL;
924 20 FpiSsm *chld = NULL;
925
926
19/22
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 7 taken 1 time.
✓ Branch 3 → 19 taken 2 times.
✓ Branch 3 → 21 taken 1 time.
✓ Branch 3 → 26 taken 1 time.
✓ Branch 3 → 31 taken 1 time.
✓ Branch 3 → 36 taken 1 time.
✓ Branch 3 → 41 taken 1 time.
✓ Branch 3 → 57 taken 1 time.
✓ Branch 3 → 65 taken 1 time.
✓ Branch 3 → 69 taken 1 time.
✓ Branch 3 → 73 taken 1 time.
✓ Branch 3 → 77 taken 1 time.
✓ Branch 3 → 85 taken 1 time.
✗ Branch 3 → 101 not taken.
✗ Branch 3 → 105 not taken.
✓ Branch 3 → 109 taken 1 time.
✓ Branch 3 → 119 taken 1 time.
✓ Branch 3 → 125 taken 1 time.
✓ Branch 3 → 132 taken 1 time.
✓ Branch 3 → 138 taken 1 time.
✗ Branch 3 → 140 not taken.
20 switch (fpi_ssm_get_cur_state (ssm))
927 {
928 1 case ELANSPI_INIT_READ_STATUS1:
929 1 xfer = elanspi_read_status (self, &self->sensor_status);
930 1 xfer->ssm = ssm;
931 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
932 21 return;
933
934 1 case ELANSPI_INIT_HWSWRESET:
935 1 fp_dbg ("<init> got status %02x", self->sensor_status);
936 1 elanspi_do_hwreset (self, &err);
937 1 fp_dbg ("<init> sync hw reset");
938
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 14 taken 1 time.
1 if (err)
939 {
940 fp_err ("<init> sync hw reset failed");
941 fpi_ssm_mark_failed (ssm, err);
942 return;
943 }
944 1 do_sw_reset:
945 2 xfer = elanspi_do_swreset (self);
946 2 xfer->ssm = ssm;
947 2 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
948 2 return;
949
950 2 case ELANSPI_INIT_SWRESETDELAY1:
951 case ELANSPI_INIT_SWRESETDELAY2:
952 2 fpi_ssm_next_state_delayed (ssm, 4);
953 2 return;
954
955 1 case ELANSPI_INIT_READ_HEIGHT:
956 1 fp_dbg ("<init> sw reset ok");
957 1 xfer = elanspi_read_height (self, &self->sensor_height);
958 1 xfer->ssm = ssm;
959 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
960 1 return;
961
962 1 case ELANSPI_INIT_READ_WIDTH:
963 1 self->sensor_height += 1;
964 1 fp_dbg ("<init> raw height = %d", self->sensor_height);
965 1 xfer = elanspi_read_width (self, &self->sensor_width);
966 1 xfer->ssm = ssm;
967 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
968 1 return;
969
970 1 case ELANSPI_INIT_READ_REG17:
971 1 self->sensor_width += 1;
972 1 fp_dbg ("<init> raw width = %d", self->sensor_width);
973 1 xfer = elanspi_read_register (self, 0x17, &self->sensor_reg_17);
974 1 xfer->ssm = ssm;
975 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
976 1 return;
977
978 1 case ELANSPI_INIT_READ_VERSION:
979 1 fp_dbg ("<init> raw reg17 = %d", self->sensor_reg_17);
980 1 xfer = elanspi_read_version (self, &self->sensor_raw_version);
981 1 xfer->ssm = ssm;
982 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
983 1 return;
984
985 1 case ELANSPI_INIT_SWRESET2:
986 1 fp_dbg ("<init> raw version = %02x", self->sensor_raw_version);
987 1 elanspi_determine_sensor (self, &err);
988
1/2
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 47 taken 1 time.
1 if (err)
989 {
990 fp_err ("<init> sensor detection error");
991 fpi_ssm_mark_failed (ssm, err);
992 return;
993 }
994 /* allocate memory */
995
1/2
✗ Branch 47 → 48 not taken.
✓ Branch 47 → 49 taken 1 time.
1 g_clear_pointer (&self->bg_image, g_free);
996
1/2
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 1 time.
1 g_clear_pointer (&self->last_image, g_free);
997
1/2
✗ Branch 51 → 52 not taken.
✓ Branch 51 → 53 taken 1 time.
1 g_clear_pointer (&self->prev_frame_image, g_free);
998 1 self->last_image = g_malloc0 (self->sensor_width * self->sensor_height * 2);
999 1 self->bg_image = g_malloc0 (self->sensor_width * self->sensor_height * 2);
1000 1 self->prev_frame_image = g_malloc0 (self->sensor_width * self->sensor_height * 2);
1001 /* reset again */
1002 1 goto do_sw_reset;
1003
1004 1 case ELANSPI_INIT_OTP_READ_VREF1:
1005 /* is this sensor otp? */
1006
1/2
✗ Branch 57 → 58 not taken.
✓ Branch 57 → 60 taken 1 time.
1 if (!self->sensor_otp)
1007 {
1008 /* go to calibration */
1009 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_CALIBRATE);
1010 return;
1011 }
1012 /* otherwise, begin otp */
1013 1 self->old_data.otp_timeout = g_get_monotonic_time () + ELANSPI_OTP_TIMEOUT_USEC;
1014 1 xfer = elanspi_read_register (self, 0x3d, &self->sensor_reg_vref1);
1015 1 xfer->ssm = ssm;
1016 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1017 1 return;
1018
1019 1 case ELANSPI_INIT_OTP_WRITE_VREF1:
1020 /* mask out low bits */
1021 1 self->sensor_reg_vref1 &= 0x3f;
1022 1 xfer = elanspi_write_register (self, 0x3d, self->sensor_reg_vref1);
1023 1 xfer->ssm = ssm;
1024 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1025 1 return;
1026
1027 1 case ELANSPI_INIT_OTP_WRITE_0x28:
1028 1 xfer = elanspi_write_register (self, 0x28, 0x78);
1029 1 xfer->ssm = ssm;
1030 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1031 1 return;
1032
1033 /* begin loop */
1034 1 case ELANSPI_INIT_OTP_LOOP_READ_0x28:
1035 /* begin read of 0x28 */
1036 1 xfer = elanspi_read_register (self, 0x28, &self->sensor_reg_28);
1037 1 xfer->ssm = ssm;
1038 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1039 1 return;
1040
1041 1 case ELANSPI_INIT_OTP_LOOP_READ_0x27:
1042
1/2
✗ Branch 77 → 78 not taken.
✓ Branch 77 → 81 taken 1 time.
1 if (self->sensor_reg_28 & 0x40)
1043 {
1044 /* try again */
1045 fp_dbg ("<init/otp> looping");
1046 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_OTP_LOOP_READ_0x28);
1047 return;
1048 }
1049 /* otherwise, read reg 27 */
1050 1 xfer = elanspi_read_register (self, 0x27, &self->sensor_reg_27);
1051 1 xfer->ssm = ssm;
1052 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1053 1 return;
1054
1055 1 case ELANSPI_INIT_OTP_LOOP_UPDATEDAC_READ_DAC2:
1056 /* if high bit set, exit with mode 2 */
1057
1/2
✓ Branch 85 → 86 taken 1 time.
✗ Branch 85 → 88 not taken.
1 if (self->sensor_reg_27 & 0x80)
1058 {
1059 1 self->sensor_vcm_mode = 2;
1060 1 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_OTP_WRITE_0xb);
1061 1 return;
1062 }
1063 /* if low two bits are not set, loop */
1064 if ((self->sensor_reg_27 & 6) != 6)
1065 {
1066 /* have we hit the timeout */
1067 if (g_get_monotonic_time () > self->old_data.otp_timeout)
1068 {
1069 fp_warn ("<init/otp> timed out waiting for vcom detection");
1070 self->sensor_vcm_mode = 2;
1071 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_OTP_WRITE_0xb);
1072 return;
1073 }
1074 /* try again */
1075 fp_dbg ("<init/otp> looping");
1076 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_OTP_LOOP_READ_0x28);
1077 return;
1078 }
1079 /* otherwise, set vcm mode from low bit and read dac2 */
1080 self->sensor_vcm_mode = (self->sensor_reg_27 & 1) + 1;
1081 xfer = elanspi_read_register (self, 0x7, &self->sensor_reg_dac2);
1082 xfer->ssm = ssm;
1083 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1084 return;
1085
1086 case ELANSPI_INIT_OTP_LOOP_UPDATEDAC_WRITE_DAC2:
1087 /* set high bit and rewrite */
1088 self->sensor_reg_dac2 |= 0x80;
1089 xfer = elanspi_write_register (self, 0x7, self->sensor_reg_dac2);
1090 xfer->ssm = ssm;
1091 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1092 return;
1093
1094 case ELANSPI_INIT_OTP_LOOP_UPDATEDAC_WRITE_10:
1095 xfer = elanspi_write_register (self, 0xa, 0x97);
1096 xfer->ssm = ssm;
1097 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1098 return;
1099
1100 /* end loop, joins to here on early exits */
1101 1 case ELANSPI_INIT_OTP_WRITE_0xb:
1102 1 fp_dbg ("<init/otp> got vcm mode = %d", self->sensor_vcm_mode);
1103 /* if mode is 0, skip to calibration */
1104
1/2
✗ Branch 110 → 111 not taken.
✓ Branch 110 → 113 taken 1 time.
1 if (self->sensor_vcm_mode == 0)
1105 {
1106 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_CALIBRATE);
1107 return;
1108 }
1109
1/2
✗ Branch 113 → 114 not taken.
✓ Branch 113 → 115 taken 1 time.
1 xfer = elanspi_write_register (self, 0xb, self->sensor_vcm_mode == 2 ? 0x72 : 0x71);
1110 1 xfer->ssm = ssm;
1111 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1112 1 return;
1113
1114 1 case ELANSPI_INIT_OTP_WRITE_0xc:
1115
1/2
✗ Branch 119 → 120 not taken.
✓ Branch 119 → 121 taken 1 time.
1 xfer = elanspi_write_register (self, 0xc, self->sensor_vcm_mode == 2 ? 0x62 : 0x49);
1116 1 xfer->ssm = ssm;
1117 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1118 1 return;
1119
1120 1 case ELANSPI_INIT_CALIBRATE:
1121 1 fp_dbg ("<init/calibrate> starting calibrate");
1122 /* if sensor is hv */
1123
1/2
✗ Branch 126 → 127 not taken.
✓ Branch 126 → 128 taken 1 time.
1 if (self->sensor_id == 0xe)
1124 chld = fpi_ssm_new_full (dev, elanspi_calibrate_hv_handler, ELANSPI_CALIBHV_NSTATES, ELANSPI_CALIBHV_PROTECT, "HV calibrate");
1125 else
1126 1 chld = fpi_ssm_new_full (dev, elanspi_calibrate_old_handler, ELANSPI_CALIBOLD_NSTATES, ELANSPI_CALIBOLD_PROTECT, "old calibrate");
1127 1 fpi_ssm_silence_debug (chld);
1128 1 fpi_ssm_start_subsm (ssm, chld);
1129 1 return;
1130
1131 1 case ELANSPI_INIT_BG_CAPTURE:
1132
1/2
✗ Branch 132 → 133 not taken.
✓ Branch 132 → 134 taken 1 time.
1 if (self->sensor_id == 0xe)
1133 chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES);
1134 else
1135 1 chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES);
1136 1 fpi_ssm_silence_debug (chld);
1137 1 fpi_ssm_start_subsm (ssm, chld);
1138 1 return;
1139
1140 1 case ELANSPI_INIT_BG_SAVE:
1141 1 memcpy (self->bg_image, self->last_image, self->sensor_height * self->sensor_width * 2);
1142 1 fpi_ssm_mark_completed (ssm);
1143 1 return;
1144 }
1145 }
1146
1147 enum elanspi_guess_result {
1148 ELANSPI_GUESS_FINGERPRINT,
1149 ELANSPI_GUESS_EMPTY,
1150 ELANSPI_GUESS_UNKNOWN
1151 };
1152
1153 /* in place correct image, returning number of invalid pixels */
1154 static gint
1155 96 elanspi_correct_with_bg (FpiDeviceElanSpi *self, guint16 *raw_image)
1156 {
1157 96 gint count = 0;
1158
1159
2/2
✓ Branch 7 → 3 taken 884736 times.
✓ Branch 7 → 8 taken 96 times.
884832 for (int i = 0; i < self->sensor_width * self->sensor_height; i += 1)
1160 {
1161
2/2
✓ Branch 3 → 4 taken 104162 times.
✓ Branch 3 → 5 taken 780574 times.
884736 if (raw_image[i] < self->bg_image[i])
1162 {
1163 104162 count += 1;
1164 104162 raw_image[i] = 0;
1165 }
1166 else
1167 {
1168 780574 raw_image[i] -= self->bg_image[i];
1169 }
1170 }
1171
1172 96 return count;
1173 }
1174
1175 static guint16
1176 792576 elanspi_lookup_pixel_with_rotation (FpiDeviceElanSpi *self, const guint16 *data_in, int y, int x)
1177 {
1178 792576 int rotation = fpi_device_get_driver_data (FP_DEVICE (self)) & 3;
1179 792576 gint x1 = x, y1 = y;
1180
1181
1/2
✓ Branch 3 → 4 taken 792576 times.
✗ Branch 3 → 5 not taken.
792576 if (rotation == ELANSPI_180_ROTATE)
1182 {
1183 792576 x1 = (self->sensor_width - x - 1);
1184 792576 y1 = (self->sensor_height - y - 1);
1185 }
1186 else if (rotation == ELANSPI_90LEFT_ROTATE)
1187 {
1188 x1 = y;
1189 y1 = (self->sensor_width - x - 1);
1190 }
1191 else if (rotation == ELANSPI_90RIGHT_ROTATE)
1192 {
1193 x1 = (self->sensor_height - y - 1);
1194 y1 = x;
1195 }
1196 792576 return data_in[y1 * self->sensor_width + x1];
1197 }
1198
1199 static enum elanspi_guess_result
1200 73 elanspi_guess_image (FpiDeviceElanSpi *self, guint16 *raw_image)
1201 {
1202 73 g_autofree guint16 * image_copy = g_malloc0 (self->sensor_height * self->sensor_width * 2);
1203 73 guint8 frame_width, frame_height;
1204
1205 /* make clang happy about div0 */
1206 73 frame_width = self->frame_width;
1207 73 frame_height = self->frame_height;
1208
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 73 times.
73 g_assert (frame_width && frame_height);
1209
1210 73 memcpy (image_copy, raw_image, self->sensor_height * self->sensor_width * 2);
1211
1212 73 gint invalid_percent = (100 * elanspi_correct_with_bg (self, image_copy)) / (self->sensor_height * self->sensor_width);
1213 73 gint is_fp = 0, is_empty = 0;
1214
1215 73 gint64 mean = 0;
1216 73 gint64 sq_stddev = 0;
1217
1218
2/2
✓ Branch 11 → 9 taken 3139 times.
✓ Branch 11 → 12 taken 73 times.
3212 for (int j = 0; j < frame_height; j += 1)
1219
2/2
✓ Branch 9 → 7 taken 301344 times.
✓ Branch 9 → 10 taken 3139 times.
304483 for (int i = 0; i < frame_width; i += 1)
1220 301344 mean += (gint64) elanspi_lookup_pixel_with_rotation (self, image_copy, j, i);
1221
1222 73 mean /= (frame_width * frame_height);
1223
1224
2/2
✓ Branch 17 → 15 taken 3139 times.
✓ Branch 17 → 18 taken 73 times.
3212 for (int j = 0; j < frame_height; j += 1)
1225
2/2
✓ Branch 15 → 13 taken 301344 times.
✓ Branch 15 → 16 taken 3139 times.
304483 for (int i = 0; i < frame_width; i += 1)
1226 {
1227 301344 gint64 k = (gint64) elanspi_lookup_pixel_with_rotation (self, image_copy, j, i) - mean;
1228 301344 sq_stddev += k * k;
1229 }
1230
1231 73 sq_stddev /= (frame_width * frame_height);
1232
1233
2/2
✓ Branch 18 → 19 taken 29 times.
✓ Branch 18 → 21 taken 44 times.
73 if (invalid_percent < ELANSPI_MAX_REAL_INVALID_PERCENT)
1234 is_fp += 1;
1235
2/2
✓ Branch 19 → 20 taken 27 times.
✓ Branch 19 → 21 taken 2 times.
29 if (invalid_percent > ELANSPI_MIN_EMPTY_INVALID_PERCENT)
1236 27 is_empty += 1;
1237
1238
2/2
✓ Branch 21 → 22 taken 40 times.
✓ Branch 21 → 23 taken 33 times.
73 if (sq_stddev > ELANSPI_MIN_REAL_STDDEV)
1239 40 is_fp += 1;
1240
2/2
✓ Branch 23 → 24 taken 27 times.
✓ Branch 23 → 25 taken 6 times.
73 if (sq_stddev < ELANSPI_MAX_EMPTY_STDDEV)
1241 27 is_empty += 1;
1242
1243 73 fp_dbg ("<guess> stddev=%" G_GUINT64_FORMAT "d, ip=%d, is_fp=%d, is_empty=%d", sq_stddev, invalid_percent, is_fp, is_empty);
1244
1245
2/2
✓ Branch 26 → 27 taken 27 times.
✓ Branch 26 → 29 taken 46 times.
73 if (is_fp > is_empty)
1246 return ELANSPI_GUESS_FINGERPRINT;
1247
1/2
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 27 times.
27 else if (is_empty > is_fp)
1248 return ELANSPI_GUESS_EMPTY;
1249 else
1250 return ELANSPI_GUESS_UNKNOWN;
1251 }
1252
1253 /* returns TRUE when the waiting is complete */
1254 static gboolean
1255 49 elanspi_check_waitupdown_done (FpiDeviceElanSpi *self, enum elanspi_guess_result target)
1256 {
1257 49 enum elanspi_guess_result guess = elanspi_guess_image (self, self->last_image);
1258
1259
1/2
✓ Branch 3 → 4 taken 49 times.
✗ Branch 3 → 7 not taken.
49 if (guess == ELANSPI_GUESS_UNKNOWN)
1260 return FALSE;
1261
2/2
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 6 taken 45 times.
49 if (guess == target)
1262 {
1263 4 self->finger_wait_debounce += 1;
1264 4 return self->finger_wait_debounce == ELANSPI_MIN_FRAMES_DEBOUNCE;
1265 }
1266 else
1267 {
1268 45 self->finger_wait_debounce = 0;
1269 45 return FALSE;
1270 }
1271 }
1272
1273 static int
1274 951265 cmp_u16 (const void *a, const void *b)
1275 {
1276 951265 return (int) (*(guint16 *) a - *(guint16 *) b);
1277 }
1278
1279 static void
1280 23 elanspi_process_frame (FpiDeviceElanSpi *self, const guint16 *data_in, guint8 *data_out)
1281 23 {
1282 23 size_t frame_size = self->frame_width * self->frame_height;
1283 23 guint16 data_in_sorted[frame_size];
1284
1285
2/2
✓ Branch 7 → 8 taken 989 times.
✓ Branch 7 → 9 taken 23 times.
1012 for (int i = 0, offset = 0; i < self->frame_height; i += 1)
1286
2/2
✓ Branch 5 → 3 taken 94944 times.
✓ Branch 5 → 6 taken 989 times.
95933 for (int j = 0; j < self->frame_width; j += 1)
1287 94944 data_in_sorted[offset++] = elanspi_lookup_pixel_with_rotation (self, data_in, i, j);
1288
1289 23 qsort (data_in_sorted, frame_size, 2, cmp_u16);
1290 23 guint16 lvl0 = data_in_sorted[0];
1291 23 guint16 lvl1 = data_in_sorted[frame_size * 3 / 10];
1292 23 guint16 lvl2 = data_in_sorted[frame_size * 65 / 100];
1293 23 guint16 lvl3 = data_in_sorted[frame_size - 1];
1294
1295 23 lvl1 = MAX (lvl1, lvl0 + 1);
1296 23 lvl2 = MAX (lvl2, lvl1 + 1);
1297 23 lvl3 = MAX (lvl3, lvl2 + 1);
1298
1299
2/2
✓ Branch 22 → 23 taken 989 times.
✓ Branch 22 → 24 taken 23 times.
1012 for (int i = 0; i < self->frame_height; i += 1)
1300 {
1301
2/2
✓ Branch 20 → 11 taken 94944 times.
✓ Branch 20 → 21 taken 989 times.
95933 for (int j = 0; j < self->frame_width; j += 1)
1302 {
1303 94944 guint16 px = elanspi_lookup_pixel_with_rotation (self, data_in, i, j);
1304
1/2
✓ Branch 12 → 13 taken 94944 times.
✗ Branch 12 → 19 not taken.
94944 if (px < lvl0)
1305 {
1306 px = 0;
1307 }
1308
1/2
✓ Branch 13 → 14 taken 94944 times.
✗ Branch 13 → 19 not taken.
94944 else if (px > lvl3)
1309 {
1310 px = 255;
1311 }
1312 else
1313 {
1314
2/2
✓ Branch 14 → 15 taken 28460 times.
✓ Branch 14 → 16 taken 66484 times.
94944 if (lvl0 <= px && px < lvl1)
1315 28460 px = (px - lvl0) * 99 / (lvl1 - lvl0);
1316
2/2
✓ Branch 16 → 17 taken 33232 times.
✓ Branch 16 → 18 taken 33252 times.
66484 else if (lvl1 <= px && px < lvl2)
1317 33232 px = 99 + ((px - lvl1) * 56 / (lvl2 - lvl1));
1318 else /* (lvl2 <= px && px <= lvl3) */
1319 33252 px = 155 + ((px - lvl2) * 100 / (lvl3 - lvl2));
1320 }
1321 94944 *data_out = px;
1322 94944 data_out += 1;
1323 }
1324 }
1325 23 }
1326
1327 static unsigned char
1328 152172653 elanspi_fp_assembling_get_pixel (struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, unsigned int y)
1329 {
1330 152172653 return frame->data[y * ctx->frame_width + x];
1331 }
1332
1333 static void
1334 1 elanspi_fp_frame_stitch_and_submit (FpiDeviceElanSpi *self)
1335 {
1336 2 g_autoptr(FpImage) img = NULL;
1337
1/2
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 10 not taken.
1 g_autoptr(FpImage) scaled = NULL;
1338 1 struct fpi_frame_asmbl_ctx assembling_ctx = {
1339 1 .image_width = (self->frame_width * 3) / 2,
1340
1341 1 .frame_width = self->frame_width,
1342 1 .frame_height = self->frame_height,
1343
1344 .get_pixel = elanspi_fp_assembling_get_pixel,
1345 };
1346
1347 /* stitch image */
1348 1 GSList *frame_start = g_slist_nth (self->fp_frame_list, ELANSPI_SWIPE_FRAMES_DISCARD);
1349
1350 1 fpi_do_movement_estimation (&assembling_ctx, frame_start);
1351 1 img = fpi_assemble_frames (&assembling_ctx, frame_start);
1352 1 scaled = fpi_image_resize (img, 2, 2);
1353
1354 1 scaled->flags |= FPI_IMAGE_PARTIAL | FPI_IMAGE_COLORS_INVERTED;
1355
1356 /* submit image */
1357 1 fpi_image_device_image_captured (FP_IMAGE_DEVICE (self), g_steal_pointer (&scaled));
1358
1359 /* clean out frame data */
1360
1/2
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 10 not taken.
1 g_slist_free_full (g_steal_pointer (&self->fp_frame_list), g_free);
1361 1 }
1362
1363 static gint64
1364 22 elanspi_get_frame_diff_stddev_sq (FpiDeviceElanSpi *self, guint16 *frame1, guint16 *frame2)
1365 {
1366 22 gint64 mean = 0;
1367 22 gint64 sq_stddev = 0;
1368
1369
2/2
✓ Branch 4 → 3 taken 202752 times.
✓ Branch 4 → 5 taken 22 times.
202774 for (int j = 0; j < (self->sensor_height * self->sensor_width); j += 1)
1370 202752 mean += abs ((int) frame1[j] - (int) frame2[j]);
1371
1372
2/4
✓ Branch 5 → 6 taken 22 times.
✗ Branch 5 → 8 not taken.
✓ Branch 6 → 7 taken 22 times.
✗ Branch 6 → 8 not taken.
22 g_assert (self->sensor_height && self->sensor_width); /* make clang happy about div0 */
1373 22 mean /= (self->sensor_height * self->sensor_width);
1374
1375
2/2
✓ Branch 10 → 9 taken 202752 times.
✓ Branch 10 → 11 taken 22 times.
202774 for (int j = 0; j < (self->sensor_height * self->sensor_width); j += 1)
1376 {
1377 202752 gint64 k = abs ((int) frame1[j] - (int) frame2[j]) - mean;
1378 202752 sq_stddev += k * k;
1379 }
1380
1381 22 sq_stddev /= (self->sensor_height * self->sensor_width);
1382
1383 22 return sq_stddev;
1384 }
1385
1386 static void
1387 24 elanspi_fp_frame_handler (FpiSsm *ssm, FpiDeviceElanSpi *self)
1388 {
1389 48 g_autofree struct fpi_frame *this_frame = NULL;
1390
1391
1/3
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 6 not taken.
✓ Branch 3 → 16 taken 24 times.
24 switch (elanspi_guess_image (self, self->last_image))
1392 {
1393 case ELANSPI_GUESS_UNKNOWN:
1394 fp_dbg ("<fp_frame> unknown, ignore...");
1395 break;
1396
1397 case ELANSPI_GUESS_EMPTY:
1398 self->fp_empty_counter += 1;
1399 fp_dbg ("<fp_frame> got empty");
1400 if (self->fp_empty_counter > 1)
1401 {
1402 fp_dbg ("<fp_frame> have enough debounce");
1403 if (g_slist_length (self->fp_frame_list) >= ELANSPI_MIN_FRAMES_SWIPE)
1404 {
1405 fp_dbg ("<fp_frame> have enough frames, submitting");
1406 elanspi_fp_frame_stitch_and_submit (self);
1407 }
1408 else
1409 {
1410 fp_dbg ("<fp_frame> not enough frames, reporting short swipe");
1411 fpi_image_device_retry_scan (FP_IMAGE_DEVICE (self), FP_DEVICE_RETRY_TOO_SHORT);
1412 }
1413 goto finish_capture;
1414 }
1415 break;
1416
1417 24 case ELANSPI_GUESS_FINGERPRINT:
1418
1/4
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 24 taken 24 times.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 24 not taken.
24 if (self->fp_empty_counter && self->fp_frame_list)
1419 {
1420 if (self->fp_empty_counter < 1)
1421 {
1422 fp_dbg ("<fp_frame> possible bounced fp");
1423 break;
1424 }
1425 else
1426 {
1427 fp_dbg ("<fp_frame> too many empties, clearing list");
1428 g_slist_free_full (g_steal_pointer (&self->fp_frame_list), g_free);
1429 self->fp_empty_counter = 0;
1430 }
1431 }
1432
1433
2/2
✓ Branch 25 → 26 taken 1 time.
✓ Branch 25 → 29 taken 23 times.
24 if (g_slist_length (self->fp_frame_list) > ELANSPI_MAX_FRAMES_SWIPE)
1434 {
1435 1 fp_dbg ("<fp_frame> have enough frames, exiting now");
1436 1 elanspi_fp_frame_stitch_and_submit (self);
1437 1 goto finish_capture;
1438 }
1439
1440 /* append image */
1441 23 this_frame = g_malloc0 (self->sensor_height * self->sensor_width + sizeof (struct fpi_frame));
1442 23 elanspi_correct_with_bg (self, self->last_image);
1443 23 elanspi_process_frame (self, self->last_image, this_frame->data);
1444
1445
2/2
✓ Branch 32 → 33 taken 22 times.
✓ Branch 32 → 38 taken 1 time.
23 if (self->fp_frame_list)
1446 {
1447 22 gint difference = elanspi_get_frame_diff_stddev_sq (self, self->last_image, self->prev_frame_image);
1448 22 fp_dbg ("<fp_frame> diff = %d", difference);
1449
2/2
✓ Branch 35 → 36 taken 1 time.
✓ Branch 35 → 38 taken 21 times.
22 if (difference < ELANSPI_MIN_FRAME_TO_FRAME_DIFF)
1450 {
1451 1 fp_dbg ("<fp_frame> ignoring b.c. difference is too small");
1452 1 break;
1453 }
1454 }
1455 22 self->fp_frame_list = g_slist_prepend (self->fp_frame_list, g_steal_pointer (&this_frame));
1456 22 memcpy (self->prev_frame_image, self->last_image, self->sensor_height * self->sensor_width * 2);
1457 22 break;
1458 }
1459
1460
1/2
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 42 taken 23 times.
23 if (self->sensor_id == 0xe)
1461 fpi_ssm_jump_to_state_delayed (ssm, ELANSPI_FPCAPT_FP_CAPTURE, ELANSPI_HV_SENSOR_FRAME_DELAY);
1462 else
1463 23 fpi_ssm_jump_to_state (ssm, ELANSPI_FPCAPT_FP_CAPTURE);
1464
1465 return;
1466
1467 1 finish_capture:
1468 /* prepare for wait up */
1469 1 self->finger_wait_debounce = 0;
1470 1 fpi_ssm_jump_to_state (ssm, ELANSPI_FPCAPT_WAITUP_CAPTURE);
1471 1 return;
1472
1473 }
1474
1475 static void
1476 147 elanspi_fp_capture_ssm_handler (FpiSsm *ssm, FpDevice *dev)
1477 {
1478 147 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1479 147 FpiSsm *chld = NULL;
1480
1481
5/6
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 6 taken 73 times.
✓ Branch 3 → 17 taken 27 times.
✓ Branch 3 → 25 taken 24 times.
✓ Branch 3 → 27 taken 22 times.
✗ Branch 3 → 34 not taken.
147 switch (fpi_ssm_get_cur_state (ssm))
1482 {
1483 1 case ELANSPI_FPCAPT_INIT:
1484 1 self->finger_wait_debounce = 0;
1485
1486 1 fpi_ssm_next_state (ssm);
1487 1 return;
1488
1489 73 case ELANSPI_FPCAPT_WAITDOWN_CAPTURE:
1490 case ELANSPI_FPCAPT_WAITUP_CAPTURE:
1491 case ELANSPI_FPCAPT_FP_CAPTURE:
1492 /* check if we are deactivating */
1493
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 11 taken 73 times.
73 if (self->deactivating)
1494 {
1495 fp_dbg ("<capture> got deactivate; exiting");
1496
1497 self->deactivating = FALSE;
1498 fpi_ssm_mark_completed (ssm);
1499
1500 /* mark deactivate done */
1501 fpi_image_device_deactivate_complete (FP_IMAGE_DEVICE (dev), NULL);
1502
1503 return;
1504 }
1505 /* if sensor is hv */
1506
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 73 times.
73 if (self->sensor_id == 0xe)
1507 chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES);
1508 else
1509 73 chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES);
1510 73 fpi_ssm_silence_debug (chld);
1511 73 fpi_ssm_start_subsm (ssm, chld);
1512 73 return;
1513
1514 27 case ELANSPI_FPCAPT_WAITDOWN_PROCESS:
1515
2/2
✓ Branch 18 → 19 taken 26 times.
✓ Branch 18 → 21 taken 1 time.
27 if (!elanspi_check_waitupdown_done (self, ELANSPI_GUESS_FINGERPRINT))
1516 {
1517 /* take another image */
1518 26 fpi_ssm_jump_to_state (ssm, ELANSPI_FPCAPT_WAITDOWN_CAPTURE);
1519 26 return;
1520 }
1521
1522 /* prepare to take actual image */
1523 1 self->finger_wait_debounce = 0;
1524 1 g_slist_free_full (g_steal_pointer (&self->fp_frame_list), g_free);
1525 1 self->fp_empty_counter = 0;
1526
1527 /* report finger status */
1528 1 fpi_image_device_report_finger_status (FP_IMAGE_DEVICE (self), TRUE);
1529
1530 /* jump */
1531 1 fpi_ssm_jump_to_state (ssm, ELANSPI_FPCAPT_FP_CAPTURE);
1532 1 return;
1533
1534 24 case ELANSPI_FPCAPT_FP_PROCESS:
1535 24 elanspi_fp_frame_handler (ssm, self);
1536 24 return;
1537
1538 22 case ELANSPI_FPCAPT_WAITUP_PROCESS:
1539
2/2
✓ Branch 28 → 29 taken 21 times.
✓ Branch 28 → 31 taken 1 time.
22 if (!elanspi_check_waitupdown_done (self, ELANSPI_GUESS_EMPTY))
1540 {
1541 /* take another image */
1542 21 fpi_ssm_jump_to_state (ssm, ELANSPI_FPCAPT_WAITUP_CAPTURE);
1543 21 return;
1544 }
1545
1546 /* Immediately set capturing to FALSE so that when report_finger_status tries to re-start
1547 * capturing in enroll we don't hit the assert since the old SSM is about to stop. */
1548 1 self->capturing = FALSE;
1549 1 fpi_image_device_report_finger_status (FP_IMAGE_DEVICE (self), FALSE);
1550
1551 /* finish */
1552 1 fpi_ssm_mark_completed (ssm);
1553 1 return;
1554 }
1555 }
1556
1557 static void
1558 1 elanspi_open (FpImageDevice *dev)
1559 {
1560 1 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1561 1 GError *err = NULL;
1562
1563 1 G_DEBUG_HERE ();
1564
1565 1 int spi_fd = open (fpi_device_get_udev_data (FP_DEVICE (dev), FPI_DEVICE_UDEV_SUBTYPE_SPIDEV), O_RDWR);
1566
1567
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 11 taken 1 time.
1 if (spi_fd < 0)
1568 {
1569 g_set_error (&err, G_IO_ERROR, g_io_error_from_errno (errno), "unable to open spi");
1570 fpi_image_device_open_complete (dev, err);
1571 return;
1572 }
1573
1574 1 self->spi_fd = spi_fd;
1575
1576 1 fpi_image_device_open_complete (dev, NULL);
1577 }
1578
1579 static void
1580 1 elanspi_close (FpImageDevice *dev)
1581 {
1582 1 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1583
1584
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 5 not taken.
1 if (self->spi_fd >= 0)
1585 {
1586 1 close (self->spi_fd);
1587 1 self->spi_fd = -1;
1588 }
1589 1 fpi_image_device_close_complete (dev, NULL);
1590 1 }
1591
1592 static void
1593 1 elanspi_init_finish (FpiSsm *ssm, FpDevice *dev, GError *error)
1594 {
1595 1 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
1596
1597 1 G_DEBUG_HERE ();
1598 1 fpi_image_device_activate_complete (idev, error);
1599 1 }
1600
1601 static void
1602 1 elanspi_activate (FpImageDevice *dev)
1603 {
1604 1 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), elanspi_init_ssm_handler, ELANSPI_INIT_NSTATES);
1605
1606 1 fpi_ssm_start (ssm, elanspi_init_finish);
1607 1 }
1608
1609 static void
1610 1 elanspi_deactivate (FpImageDevice *dev)
1611 {
1612 1 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1613
1614
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
1 if (self->capturing)
1615 {
1616 self->deactivating = TRUE;
1617 fp_dbg ("<deactivate> waiting capture to stop");
1618 }
1619 else
1620 {
1621 1 fpi_image_device_deactivate_complete (dev, NULL);
1622 }
1623 1 }
1624
1625 static void
1626 1 elanspi_fp_capture_finish (FpiSsm *ssm, FpDevice *dev, GError *error)
1627 {
1628 1 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
1629 1 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1630
1631 1 self->capturing = FALSE;
1632
1633
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 7 taken 1 time.
1 if (self->deactivating)
1634 {
1635 /* finish deactivate */
1636 if (error)
1637 g_error_free (error);
1638 self->deactivating = FALSE;
1639 fpi_image_device_deactivate_complete (idev, NULL);
1640 return;
1641 }
1642
1643 /* if there was an error, report it */
1644
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 1 time.
1 if (error)
1645 fpi_image_device_session_error (idev, error);
1646 }
1647
1648 static void
1649 8 elanspi_change_state (FpImageDevice *dev, FpiImageDeviceState state)
1650 {
1651 8 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1652
1653
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 8 taken 7 times.
8 if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
1654 {
1655
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 g_assert (self->capturing == FALSE);
1656
1657 /* start capturer */
1658 1 self->capturing = TRUE;
1659 1 fpi_ssm_start (fpi_ssm_new (FP_DEVICE (dev),
1660 elanspi_fp_capture_ssm_handler,
1661 ELANSPI_FPCAPT_NSTATES),
1662 elanspi_fp_capture_finish);
1663
1664 1 fp_dbg ("<change_state> started capturer");
1665 }
1666 else
1667 {
1668 /* todo: other states? */
1669 8 }
1670 8 }
1671
1672 static void
1673 1 fpi_device_elanspi_init (FpiDeviceElanSpi *self)
1674 {
1675 1 self->spi_fd = -1;
1676 1 self->sensor_id = 0xff;
1677 1 }
1678
1679 static void
1680 1 fpi_device_elanspi_finalize (GObject *this)
1681 {
1682 1 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (this);
1683
1684
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 4 not taken.
1 g_clear_pointer (&self->bg_image, g_free);
1685
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 6 not taken.
1 g_clear_pointer (&self->last_image, g_free);
1686
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 8 not taken.
1 g_clear_pointer (&self->prev_frame_image, g_free);
1687 1 g_slist_free_full (g_steal_pointer (&self->fp_frame_list), g_free);
1688
1689 1 G_OBJECT_CLASS (fpi_device_elanspi_parent_class)->finalize (this);
1690 1 }
1691
1692 static void
1693 125 fpi_device_elanspi_class_init (FpiDeviceElanSpiClass *klass)
1694 {
1695 125 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
1696 125 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
1697
1698 125 dev_class->id = "elanspi";
1699 125 dev_class->full_name = "ElanTech Embedded Fingerprint Sensor";
1700 125 dev_class->type = FP_DEVICE_TYPE_UDEV;
1701 125 dev_class->id_table = elanspi_id_table;
1702 125 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
1703 125 dev_class->nr_enroll_stages = 7; /* these sensors are very hit or miss, may as well record a few extras */
1704
1705 125 img_class->bz3_threshold = 24;
1706 125 img_class->img_open = elanspi_open;
1707 125 img_class->activate = elanspi_activate;
1708 125 img_class->deactivate = elanspi_deactivate;
1709 125 img_class->change_state = elanspi_change_state;
1710 125 img_class->img_close = elanspi_close;
1711
1712 125 G_OBJECT_CLASS (klass)->finalize = fpi_device_elanspi_finalize;
1713 }
1714