GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/elanspi.c
Date: 2024-05-04 14:54:39
Exec Total Coverage
Lines: 564 855 66.0%
Functions: 37 41 90.2%
Branches: 170 326 52.1%

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 <linux/hidraw.h>
27 #include <sys/ioctl.h>
28 #include <sys/fcntl.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/5
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 117 times.
✗ Branch 4 not taken.
750 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 2 not taken.
✓ Branch 3 taken 1 times.
1 if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
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 0 taken 1 times.
✗ Branch 1 not taken.
1 if (((raw_height == 0xa1) && (raw_width == 0xa1)) ||
339
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 ((raw_height == 0xd1) && (raw_width == 0x51)) ||
340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
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 0 taken 1 times.
✗ Branch 1 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 1 taken 7 times.
✗ Branch 2 not taken.
7 for (const struct elanspi_sensor_entry *entry = elanspi_sensor_table; entry->name; entry += 1)
383 {
384
5/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 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 0 not taken.
✓ Branch 1 taken 1 times.
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 1 not taken.
✓ Branch 2 taken 1 times.
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 0 not taken.
✓ Branch 1 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 0 taken 709632 times.
✓ Branch 1 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 0 taken 7315 times.
✓ Branch 1 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 1 not taken.
✓ Branch 2 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 1 not taken.
✓ Branch 2 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 1 taken 77 times.
✓ Branch 2 taken 7991 times.
✓ Branch 3 taken 7991 times.
✗ Branch 4 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 0 taken 599 times.
✓ Branch 1 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/4
✗ Branch 1 not taken.
✓ Branch 2 taken 599 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
599 if (g_get_monotonic_time () > self->capture_timeout && g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") != 0)
489 {
490 /* end with a timeout */
491 fpi_ssm_mark_failed (ssm, g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "timed out waiting for new line"));
492 return;
493 }
494 /* check again */
495 599 fpi_ssm_jump_to_state (ssm, ELANSPI_CAPTOLD_CHECK_LINEREADY);
496 599 return;
497 }
498 /* otherwise, perform a read */
499 7392 xfer = fpi_spi_transfer_new (dev, self->spi_fd);
500 7392 xfer->ssm = ssm;
501 7392 fpi_spi_transfer_write (xfer, 2);
502 7392 xfer->buffer_wr[0] = 0x10; /* receieve line */
503 7392 fpi_spi_transfer_read (xfer, self->sensor_width * 2);
504 7392 fpi_spi_transfer_submit (xfer, NULL, elanspi_capture_old_line_handler, NULL);
505 7392 return;
506 }
507 }
508
509 static void
510 50 elanspi_send_regtable_handler (FpiSsm *ssm, FpDevice *dev)
511 {
512 50 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
513 50 FpiSpiTransfer *xfer = NULL;
514 50 const struct elanspi_reg_entry *entry = fpi_ssm_get_data (ssm);
515
516
2/3
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
50 switch (fpi_ssm_get_cur_state (ssm))
517 {
518 25 case ELANSPI_WRTABLE_WRITE:
519 25 xfer = elanspi_write_register (self, entry->addr, entry->value);
520 25 xfer->ssm = ssm;
521 25 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
522 25 return;
523
524 25 case ELANSPI_WRTABLE_ITERATE:
525 25 entry += 1;
526
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1 times.
25 if (entry->addr != 0xff)
527 {
528 24 fpi_ssm_set_data (ssm, (gpointer) entry, NULL);
529 24 fpi_ssm_jump_to_state (ssm, ELANSPI_WRTABLE_WRITE);
530 24 return;
531 }
532 1 fpi_ssm_mark_completed (ssm);
533 1 return;
534 }
535 }
536
537 static FpiSsm *
538 1 elanspi_write_regtable (FpiDeviceElanSpi *self, const struct elanspi_regtable * table)
539 {
540 /* find regtable pointer */
541 1 const struct elanspi_reg_entry * starting_entry = table->other;
542
543
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 for (int i = 0; table->entries[i].table; i += 1)
544 {
545
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (table->entries[i].sid == self->sensor_id)
546 {
547 starting_entry = table->entries[i].table;
548 break;
549 }
550 }
551
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (starting_entry == NULL)
552 {
553 fp_err ("<regtable> unknown regtable for sensor %d", self->sensor_id);
554 return NULL;
555 }
556
557 1 FpiSsm * ssm = fpi_ssm_new (FP_DEVICE (self), elanspi_send_regtable_handler, ELANSPI_WRTABLE_NSTATES);
558
559 1 fpi_ssm_set_data (ssm, (gpointer) starting_entry, NULL);
560 1 return ssm;
561 }
562
563 static int
564 3 elanspi_mean_image (FpiDeviceElanSpi *self, const guint16 *img)
565 {
566 3 int total = 0;
567
568
6/10
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 9216 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 9216 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 9216 times.
✓ Branch 9 taken 1 times.
27651 for (int i = 0; i < self->sensor_width * self->sensor_height; i += 1)
569 27648 total += img[i];
570 3 return total / (self->sensor_width * self->sensor_height);
571 }
572
573 static void
574 11 elanspi_calibrate_old_handler (FpiSsm *ssm, FpDevice *dev)
575 {
576 11 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
577 11 FpiSpiTransfer *xfer = NULL;
578 11 GError *err = NULL;
579 11 FpiSsm *chld = NULL;
580 11 int mean_value = 0;
581
582
9/11
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
11 switch (fpi_ssm_get_cur_state (ssm))
583 {
584 1 case ELANSPI_CALIBOLD_UNPROTECT:
585 1 xfer = elanspi_write_register (self, 0x00, 0x5a);
586 1 xfer->ssm = ssm;
587 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
588 1 return;
589
590 1 case ELANSPI_CALIBOLD_WRITE_STARTCALIB:
591 1 xfer = elanspi_do_startcalib (self);
592 1 xfer->ssm = ssm;
593 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
594 1 return;
595
596 1 case ELANSPI_CALIBOLD_STARTCALIBDELAY:
597 1 fpi_ssm_next_state_delayed (ssm, 1);
598 1 return;
599
600 1 case ELANSPI_CALIBOLD_SEND_REGTABLE:
601 1 chld = elanspi_write_regtable (self, &elanspi_calibration_table_old);
602
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (chld == NULL)
603 {
604 err = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, "unknown calibration table for sensor");
605 fpi_ssm_mark_failed (ssm, err);
606 return;
607 }
608 1 fpi_ssm_start_subsm (ssm, chld);
609 1 return;
610
611 3 case ELANSPI_CALIBOLD_DACBASE_CAPTURE:
612 case ELANSPI_CALIBOLD_CHECKFIN_CAPTURE:
613 case ELANSPI_CALIBOLD_DACFINE_CAPTURE:
614 3 chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES);
615 3 fpi_ssm_silence_debug (chld);
616 3 fpi_ssm_start_subsm (ssm, chld);
617 3 return;
618
619 1 case ELANSPI_CALIBOLD_DACBASE_WRITE_DAC1:
620 /* compute dac */
621 1 self->old_data.dac_value = ((elanspi_mean_image (self, self->last_image) & 0xffff) + 0x80) >> 8;
622
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (0x3f < self->old_data.dac_value)
623 self->old_data.dac_value = 0x3f;
624 1 fp_dbg ("<calibold> dac init is 0x%02x", self->old_data.dac_value);
625 /* write it */
626 1 xfer = elanspi_write_register (self, 0x6, self->old_data.dac_value - 0x40);
627 1 xfer->ssm = ssm;
628 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
629 1 return;
630
631 1 case ELANSPI_CALIBOLD_WRITE_GAIN:
632 /* check if finger was present */
633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
2 if (elanspi_mean_image (self, self->last_image) >= ELANSPI_MAX_OLD_STAGE1_CALIBRATION_MEAN)
634 {
635 err = fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER, "finger on sensor during calibration");
636 fpi_ssm_mark_failed (ssm, err);
637 return;
638 }
639 /* if ok, increase gain */
640 1 xfer = elanspi_write_register (self, 0x5, 0x6f);
641 1 xfer->ssm = ssm;
642 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
643 /* initialize retry counter */
644 1 self->old_data.dacfine_retry = 0;
645 1 return;
646
647 1 case ELANSPI_CALIBOLD_DACFINE_WRITE_DAC1:
648 1 mean_value = elanspi_mean_image (self, self->last_image);
649
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (mean_value >= ELANSPI_MIN_OLD_STAGE2_CALBIRATION_MEAN && mean_value <= ELANSPI_MAX_OLD_STAGE2_CALBIRATION_MEAN)
650 {
651 /* finished calibration, goto bg */
652 1 fpi_ssm_jump_to_state (ssm, ELANSPI_CALIBOLD_PROTECT);
653 1 return;
654 }
655
656 if (mean_value < (ELANSPI_MIN_OLD_STAGE2_CALBIRATION_MEAN + (ELANSPI_MAX_OLD_STAGE2_CALBIRATION_MEAN - ELANSPI_MIN_OLD_STAGE2_CALBIRATION_MEAN) / 2))
657 self->old_data.dac_value -= 1;
658 else
659 self->old_data.dac_value += 1;
660
661 /* write it */
662 xfer = elanspi_write_register (self, 0x6, self->old_data.dac_value - 0x40);
663 xfer->ssm = ssm;
664 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
665 return;
666
667 case ELANSPI_CALIBOLD_DACFINE_LOOP:
668 /* check the retry counter */
669 self->old_data.dacfine_retry += 1;
670 if (self->old_data.dacfine_retry >= 2)
671 {
672 /* bail with calibration error */
673 err = fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER, "finger on sensor during calibration");
674 fpi_ssm_mark_failed (ssm, err);
675 return;
676 }
677 fp_dbg ("<calibold> repeating calibration for the %dth time", self->old_data.dacfine_retry);
678 /* otherwise, take another image */
679 fpi_ssm_jump_to_state (ssm, ELANSPI_CALIBOLD_DACFINE_CAPTURE);
680 return;
681
682 1 case ELANSPI_CALIBOLD_PROTECT:
683 1 fp_dbg ("<calibold> calibration ok, saving bg image");
684 1 xfer = elanspi_write_register (self, 0x00, 0x00);
685 1 xfer->ssm = ssm;
686 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
687 1 return;
688 }
689 }
690
691 static void
692 elanspi_capture_hv_image_handler (FpiSpiTransfer *transfer, FpDevice *dev, gpointer unused_data, GError *error)
693 {
694 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
695
696 if (error)
697 {
698 fpi_ssm_mark_failed (transfer->ssm, error);
699 return;
700 }
701
702 int i, outptr;
703 guint16 value = 0;
704
705 for (i = 0, outptr = 0; i < transfer->length_rd && outptr < (self->sensor_height * self->sensor_width * 2); i += 1)
706 {
707 if (transfer->buffer_rd[i] != 0xff)
708 {
709 if (outptr % 2)
710 {
711 value <<= 8;
712 value |= transfer->buffer_rd[i];
713 self->last_image[outptr / 2] = value;
714 }
715 else
716 {
717 value = transfer->buffer_rd[i];
718 }
719 outptr += 1;
720 }
721 }
722
723 if (outptr != (self->sensor_height * self->sensor_width * 2))
724 {
725 fp_warn ("<capture/hv> did not receive full image");
726 /* mark ssm failed */
727 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, "hv image receieve did not fill buffer");
728 fpi_ssm_mark_failed (transfer->ssm, error);
729 return;
730 }
731
732 fpi_ssm_mark_completed (transfer->ssm);
733 }
734
735
736 static void
737 elanspi_capture_hv_handler (FpiSsm *ssm, FpDevice *dev)
738 {
739 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
740 FpiSpiTransfer *xfer = NULL;
741
742 switch (fpi_ssm_get_cur_state (ssm))
743 {
744 case ELANSPI_CAPTHV_WRITE_CAPTURE:
745 /* reset capture state */
746 self->old_data.line_ptr = 0;
747 self->capture_timeout = g_get_monotonic_time () + ELANSPI_HV_CAPTURE_TIMEOUT_USEC;
748 xfer = elanspi_do_capture (self);
749 xfer->ssm = ssm;
750 /* these are specifically cancellable because they don't leave the device at some aribtrary line offset, since
751 * these devices only send entire images */
752 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
753 return;
754
755 case ELANSPI_CAPTHV_CHECK_READY:
756 xfer = elanspi_read_status (self, &self->sensor_status);
757 xfer->ssm = ssm;
758 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
759 return;
760
761 case ELANSPI_CAPTHV_RECV_IMAGE:
762 /* is the sensor ready? */
763 if (!(self->sensor_status & 4))
764 {
765 /* has the timeout expired? */
766 if (g_get_monotonic_time () > self->capture_timeout)
767 {
768 /* end with a timeout */
769 fpi_ssm_mark_failed (ssm, g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "timed out waiting for image"));
770 return;
771 }
772 /* check again */
773 fpi_ssm_jump_to_state (ssm, ELANSPI_CAPTHV_CHECK_READY);
774 return;
775 }
776 /* otherwise, read the image
777 * the hv sensors seem to use 128 bytes of padding(?) this is only tested on the 0xe sensors */
778 xfer = fpi_spi_transfer_new (dev, self->spi_fd);
779 xfer->ssm = ssm;
780 fpi_spi_transfer_write (xfer, 2);
781 xfer->buffer_wr[0] = 0x10; /* receieve line */
782 fpi_spi_transfer_read (xfer, self->sensor_height * (self->sensor_width * 2 + 48));
783 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), elanspi_capture_hv_image_handler, NULL);
784 return;
785 }
786 }
787
788 static void
789 elanspi_calibrate_hv_handler (FpiSsm *ssm, FpDevice *dev)
790 {
791 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
792 FpiSpiTransfer *xfer = NULL;
793 GError *err = NULL;
794 FpiSsm *chld = NULL;
795 int mean_diff = 0;
796
797 switch (fpi_ssm_get_cur_state (ssm))
798 {
799 case ELANSPI_CALIBHV_SELECT_PAGE0_0:
800 /* initialize gdac */
801 self->hv_data.gdac_value = 0x100;
802 self->hv_data.gdac_step = 0x100;
803 self->hv_data.best_gdac = 0x0;
804 self->hv_data.best_meandiff = 0xffff;
805
806 case ELANSPI_CALIBHV_SELECT_PAGE0_1:
807 xfer = elanspi_do_selectpage (self, 0);
808 xfer->ssm = ssm;
809 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
810 return;
811
812 case ELANSPI_CALIBHV_WRITE_STARTCALIB:
813 xfer = elanspi_do_startcalib (self);
814 xfer->ssm = ssm;
815 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
816 return;
817
818 case ELANSPI_CALIBHV_UNPROTECT:
819 xfer = elanspi_write_register (self, 0x00, 0x5a);
820 xfer->ssm = ssm;
821 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
822 return;
823
824 case ELANSPI_CALIBHV_SEND_REGTABLE0:
825 chld = elanspi_write_regtable (self, &elanspi_calibration_table_new_page0);
826 if (chld == NULL)
827 {
828 err = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, "unknown calibration table for sensor");
829 fpi_ssm_mark_failed (ssm, err);
830 return;
831 }
832 fpi_ssm_start_subsm (ssm, chld);
833 return;
834
835 case ELANSPI_CALIBHV_SELECT_PAGE1:
836 xfer = elanspi_do_selectpage (self, 1);
837 xfer->ssm = ssm;
838 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
839 return;
840
841 case ELANSPI_CALIBHV_SEND_REGTABLE1:
842 chld = elanspi_write_regtable (self, &elanspi_calibration_table_new_page1);
843 if (chld == NULL)
844 {
845 err = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, "unknown calibration table for sensor");
846 fpi_ssm_mark_failed (ssm, err);
847 return;
848 }
849 fpi_ssm_start_subsm (ssm, chld);
850 return;
851
852 case ELANSPI_CALIBHV_WRITE_GDAC_H:
853 case ELANSPI_CALIBHV_WRITE_BEST_GDAC_H:
854 if (fpi_ssm_get_cur_state (ssm) == ELANSPI_CALIBHV_WRITE_BEST_GDAC_H)
855 self->hv_data.gdac_value = self->hv_data.best_gdac;
856 xfer = elanspi_write_register (self, 0x06, (self->hv_data.gdac_value >> 2) & 0xff);
857 xfer->ssm = ssm;
858 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
859 return;
860
861 case ELANSPI_CALIBHV_WRITE_GDAC_L:
862 case ELANSPI_CALIBHV_WRITE_BEST_GDAC_L:
863 xfer = elanspi_write_register (self, 0x07, self->hv_data.gdac_value & 3);
864 xfer->ssm = ssm;
865 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
866 return;
867
868 case ELANSPI_CALIBHV_CAPTURE:
869 chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES);
870 fpi_ssm_silence_debug (chld);
871 fpi_ssm_start_subsm (ssm, chld);
872 return;
873
874 case ELANSPI_CALIBHV_PROCESS:
875 /* compute mean */
876 mean_diff = abs (elanspi_mean_image (self, self->last_image) - ELANSPI_HV_CALIBRATION_TARGET_MEAN);
877 if (mean_diff < 100)
878 {
879 fp_dbg ("<calibhv> calibration ok (mdiff < 100 w/ gdac=%04x)", self->hv_data.gdac_value);
880 /* exit early, jump right to protect */
881 fpi_ssm_jump_to_state (ssm, ELANSPI_CALIBHV_PROTECT);
882 return;
883 }
884 if (mean_diff < self->hv_data.best_meandiff)
885 {
886 self->hv_data.best_meandiff = mean_diff;
887 self->hv_data.best_gdac = self->hv_data.gdac_value;
888 }
889 /* shrink step */
890 self->hv_data.gdac_step /= 2;
891 if (self->hv_data.gdac_step == 0)
892 {
893 fp_dbg ("<calibhv> calibration ok (step = 0 w/ best_gdac=%04x)", self->hv_data.best_gdac);
894 /* exit, using best value */
895 fpi_ssm_jump_to_state (ssm, ELANSPI_CALIBHV_WRITE_BEST_GDAC_H);
896 return;
897 }
898 /* update gdac */
899 if (elanspi_mean_image (self, self->last_image) < ELANSPI_HV_CALIBRATION_TARGET_MEAN)
900 self->hv_data.gdac_value -= self->hv_data.gdac_step;
901 else
902 self->hv_data.gdac_value += self->hv_data.gdac_step;
903 /* advance back to capture */
904 fpi_ssm_jump_to_state (ssm, ELANSPI_CALIBHV_WRITE_GDAC_H);
905 return;
906
907 case ELANSPI_CALIBHV_PROTECT:
908 fp_dbg ("<calibhv> calibration ok, saving bg image");
909 xfer = elanspi_write_register (self, 0x00, 0x00);
910 xfer->ssm = ssm;
911 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
912 return;
913
914 }
915 }
916
917 static void
918 20 elanspi_init_ssm_handler (FpiSsm *ssm, FpDevice *dev)
919 {
920 20 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
921 20 FpiSpiTransfer *xfer = NULL;
922 20 GError *err = NULL;
923 20 FpiSsm *chld = NULL;
924
925
19/22
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✓ Branch 18 taken 1 times.
✓ Branch 19 taken 1 times.
✓ Branch 20 taken 1 times.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
20 switch (fpi_ssm_get_cur_state (ssm))
926 {
927 1 case ELANSPI_INIT_READ_STATUS1:
928 1 xfer = elanspi_read_status (self, &self->sensor_status);
929 1 xfer->ssm = ssm;
930 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
931 21 return;
932
933 1 case ELANSPI_INIT_HWSWRESET:
934 1 fp_dbg ("<init> got status %02x", self->sensor_status);
935 1 elanspi_do_hwreset (self, &err);
936 1 fp_dbg ("<init> sync hw reset");
937
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (err)
938 {
939 fp_err ("<init> sync hw reset failed");
940 fpi_ssm_mark_failed (ssm, err);
941 return;
942 }
943 1 do_sw_reset:
944 2 xfer = elanspi_do_swreset (self);
945 2 xfer->ssm = ssm;
946 2 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
947 2 return;
948
949 2 case ELANSPI_INIT_SWRESETDELAY1:
950 case ELANSPI_INIT_SWRESETDELAY2:
951 2 fpi_ssm_next_state_delayed (ssm, 4);
952 2 return;
953
954 1 case ELANSPI_INIT_READ_HEIGHT:
955 1 fp_dbg ("<init> sw reset ok");
956 1 xfer = elanspi_read_height (self, &self->sensor_height);
957 1 xfer->ssm = ssm;
958 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
959 1 return;
960
961 1 case ELANSPI_INIT_READ_WIDTH:
962 1 self->sensor_height += 1;
963 1 fp_dbg ("<init> raw height = %d", self->sensor_height);
964 1 xfer = elanspi_read_width (self, &self->sensor_width);
965 1 xfer->ssm = ssm;
966 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
967 1 return;
968
969 1 case ELANSPI_INIT_READ_REG17:
970 1 self->sensor_width += 1;
971 1 fp_dbg ("<init> raw width = %d", self->sensor_width);
972 1 xfer = elanspi_read_register (self, 0x17, &self->sensor_reg_17);
973 1 xfer->ssm = ssm;
974 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
975 1 return;
976
977 1 case ELANSPI_INIT_READ_VERSION:
978 1 fp_dbg ("<init> raw reg17 = %d", self->sensor_reg_17);
979 1 xfer = elanspi_read_version (self, &self->sensor_raw_version);
980 1 xfer->ssm = ssm;
981 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
982 1 return;
983
984 1 case ELANSPI_INIT_SWRESET2:
985 1 fp_dbg ("<init> raw version = %02x", self->sensor_raw_version);
986 1 elanspi_determine_sensor (self, &err);
987
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (err)
988 {
989 fp_err ("<init> sensor detection error");
990 fpi_ssm_mark_failed (ssm, err);
991 return;
992 }
993 /* allocate memory */
994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_clear_pointer (&self->bg_image, g_free);
995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_clear_pointer (&self->last_image, g_free);
996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_clear_pointer (&self->prev_frame_image, g_free);
997 1 self->last_image = g_malloc0 (self->sensor_width * self->sensor_height * 2);
998 1 self->bg_image = g_malloc0 (self->sensor_width * self->sensor_height * 2);
999 1 self->prev_frame_image = g_malloc0 (self->sensor_width * self->sensor_height * 2);
1000 /* reset again */
1001 1 goto do_sw_reset;
1002
1003 1 case ELANSPI_INIT_OTP_READ_VREF1:
1004 /* is this sensor otp? */
1005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!self->sensor_otp)
1006 {
1007 /* go to calibration */
1008 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_CALIBRATE);
1009 return;
1010 }
1011 /* otherwise, begin otp */
1012 1 self->old_data.otp_timeout = g_get_monotonic_time () + ELANSPI_OTP_TIMEOUT_USEC;
1013 1 xfer = elanspi_read_register (self, 0x3d, &self->sensor_reg_vref1);
1014 1 xfer->ssm = ssm;
1015 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1016 1 return;
1017
1018 1 case ELANSPI_INIT_OTP_WRITE_VREF1:
1019 /* mask out low bits */
1020 1 self->sensor_reg_vref1 &= 0x3f;
1021 1 xfer = elanspi_write_register (self, 0x3d, self->sensor_reg_vref1);
1022 1 xfer->ssm = ssm;
1023 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1024 1 return;
1025
1026 1 case ELANSPI_INIT_OTP_WRITE_0x28:
1027 1 xfer = elanspi_write_register (self, 0x28, 0x78);
1028 1 xfer->ssm = ssm;
1029 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1030 1 return;
1031
1032 /* begin loop */
1033 1 case ELANSPI_INIT_OTP_LOOP_READ_0x28:
1034 /* begin read of 0x28 */
1035 1 xfer = elanspi_read_register (self, 0x28, &self->sensor_reg_28);
1036 1 xfer->ssm = ssm;
1037 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1038 1 return;
1039
1040 1 case ELANSPI_INIT_OTP_LOOP_READ_0x27:
1041
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (self->sensor_reg_28 & 0x40)
1042 {
1043 /* try again */
1044 fp_dbg ("<init/otp> looping");
1045 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_OTP_LOOP_READ_0x28);
1046 return;
1047 }
1048 /* otherwise, read reg 27 */
1049 1 xfer = elanspi_read_register (self, 0x27, &self->sensor_reg_27);
1050 1 xfer->ssm = ssm;
1051 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1052 1 return;
1053
1054 1 case ELANSPI_INIT_OTP_LOOP_UPDATEDAC_READ_DAC2:
1055 /* if high bit set, exit with mode 2 */
1056
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->sensor_reg_27 & 0x80)
1057 {
1058 1 self->sensor_vcm_mode = 2;
1059 1 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_OTP_WRITE_0xb);
1060 1 return;
1061 }
1062 /* if low two bits are not set, loop */
1063 if ((self->sensor_reg_27 & 6) != 6)
1064 {
1065 /* have we hit the timeout */
1066 if (g_get_monotonic_time () > self->old_data.otp_timeout)
1067 {
1068 fp_warn ("<init/otp> timed out waiting for vcom detection");
1069 self->sensor_vcm_mode = 2;
1070 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_OTP_WRITE_0xb);
1071 return;
1072 }
1073 /* try again */
1074 fp_dbg ("<init/otp> looping");
1075 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_OTP_LOOP_READ_0x28);
1076 return;
1077 }
1078 /* otherwise, set vcm mode from low bit and read dac2 */
1079 self->sensor_vcm_mode = (self->sensor_reg_27 & 1) + 1;
1080 xfer = elanspi_read_register (self, 0x7, &self->sensor_reg_dac2);
1081 xfer->ssm = ssm;
1082 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1083 return;
1084
1085 case ELANSPI_INIT_OTP_LOOP_UPDATEDAC_WRITE_DAC2:
1086 /* set high bit and rewrite */
1087 self->sensor_reg_dac2 |= 0x80;
1088 xfer = elanspi_write_register (self, 0x7, self->sensor_reg_dac2);
1089 xfer->ssm = ssm;
1090 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1091 return;
1092
1093 case ELANSPI_INIT_OTP_LOOP_UPDATEDAC_WRITE_10:
1094 xfer = elanspi_write_register (self, 0xa, 0x97);
1095 xfer->ssm = ssm;
1096 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1097 return;
1098
1099 /* end loop, joins to here on early exits */
1100 1 case ELANSPI_INIT_OTP_WRITE_0xb:
1101 1 fp_dbg ("<init/otp> got vcm mode = %d", self->sensor_vcm_mode);
1102 /* if mode is 0, skip to calibration */
1103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (self->sensor_vcm_mode == 0)
1104 {
1105 fpi_ssm_jump_to_state (ssm, ELANSPI_INIT_CALIBRATE);
1106 return;
1107 }
1108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 xfer = elanspi_write_register (self, 0xb, self->sensor_vcm_mode == 2 ? 0x72 : 0x71);
1109 1 xfer->ssm = ssm;
1110 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1111 1 return;
1112
1113 1 case ELANSPI_INIT_OTP_WRITE_0xc:
1114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 xfer = elanspi_write_register (self, 0xc, self->sensor_vcm_mode == 2 ? 0x62 : 0x49);
1115 1 xfer->ssm = ssm;
1116 1 fpi_spi_transfer_submit (xfer, fpi_device_get_cancellable (dev), fpi_ssm_spi_transfer_cb, NULL);
1117 1 return;
1118
1119 1 case ELANSPI_INIT_CALIBRATE:
1120 1 fp_dbg ("<init/calibrate> starting calibrate");
1121 /* if sensor is hv */
1122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (self->sensor_id == 0xe)
1123 chld = fpi_ssm_new_full (dev, elanspi_calibrate_hv_handler, ELANSPI_CALIBHV_NSTATES, ELANSPI_CALIBHV_PROTECT, "HV calibrate");
1124 else
1125 1 chld = fpi_ssm_new_full (dev, elanspi_calibrate_old_handler, ELANSPI_CALIBOLD_NSTATES, ELANSPI_CALIBOLD_PROTECT, "old calibrate");
1126 1 fpi_ssm_silence_debug (chld);
1127 1 fpi_ssm_start_subsm (ssm, chld);
1128 1 return;
1129
1130 1 case ELANSPI_INIT_BG_CAPTURE:
1131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (self->sensor_id == 0xe)
1132 chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES);
1133 else
1134 1 chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES);
1135 1 fpi_ssm_silence_debug (chld);
1136 1 fpi_ssm_start_subsm (ssm, chld);
1137 1 return;
1138
1139 1 case ELANSPI_INIT_BG_SAVE:
1140 1 memcpy (self->bg_image, self->last_image, self->sensor_height * self->sensor_width * 2);
1141 1 fpi_ssm_mark_completed (ssm);
1142 1 return;
1143 }
1144 }
1145
1146 enum elanspi_guess_result {
1147 ELANSPI_GUESS_FINGERPRINT,
1148 ELANSPI_GUESS_EMPTY,
1149 ELANSPI_GUESS_UNKNOWN
1150 };
1151
1152 /* in place correct image, returning number of invalid pixels */
1153 static gint
1154 96 elanspi_correct_with_bg (FpiDeviceElanSpi *self, guint16 *raw_image)
1155 {
1156 96 gint count = 0;
1157
1158
2/2
✓ Branch 0 taken 884736 times.
✓ Branch 1 taken 96 times.
884832 for (int i = 0; i < self->sensor_width * self->sensor_height; i += 1)
1159 {
1160
2/2
✓ Branch 0 taken 104162 times.
✓ Branch 1 taken 780574 times.
884736 if (raw_image[i] < self->bg_image[i])
1161 {
1162 104162 count += 1;
1163 104162 raw_image[i] = 0;
1164 }
1165 else
1166 {
1167 780574 raw_image[i] -= self->bg_image[i];
1168 }
1169 }
1170
1171 96 return count;
1172 }
1173
1174 static guint16
1175 792576 elanspi_lookup_pixel_with_rotation (FpiDeviceElanSpi *self, const guint16 *data_in, int y, int x)
1176 {
1177 792576 int rotation = fpi_device_get_driver_data (FP_DEVICE (self)) & 3;
1178 792576 gint x1 = x, y1 = y;
1179
1180
1/2
✓ Branch 0 taken 792576 times.
✗ Branch 1 not taken.
792576 if (rotation == ELANSPI_180_ROTATE)
1181 {
1182 792576 x1 = (self->sensor_width - x - 1);
1183 792576 y1 = (self->sensor_height - y - 1);
1184 }
1185 else if (rotation == ELANSPI_90LEFT_ROTATE)
1186 {
1187 x1 = y;
1188 y1 = (self->sensor_width - x - 1);
1189 }
1190 else if (rotation == ELANSPI_90RIGHT_ROTATE)
1191 {
1192 x1 = (self->sensor_height - y - 1);
1193 y1 = x;
1194 }
1195 792576 return data_in[y1 * self->sensor_width + x1];
1196 }
1197
1198 static enum elanspi_guess_result
1199 73 elanspi_guess_image (FpiDeviceElanSpi *self, guint16 *raw_image)
1200 {
1201 73 g_autofree guint16 * image_copy = g_malloc0 (self->sensor_height * self->sensor_width * 2);
1202 73 guint8 frame_width, frame_height;
1203
1204 /* make clang happy about div0 */
1205 73 frame_width = self->frame_width;
1206 73 frame_height = self->frame_height;
1207
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 g_assert (frame_width && frame_height);
1208
1209 73 memcpy (image_copy, raw_image, self->sensor_height * self->sensor_width * 2);
1210
1211 73 gint invalid_percent = (100 * elanspi_correct_with_bg (self, image_copy)) / (self->sensor_height * self->sensor_width);
1212 73 gint is_fp = 0, is_empty = 0;
1213
1214 73 gint64 mean = 0;
1215 73 gint64 sq_stddev = 0;
1216
1217
2/2
✓ Branch 0 taken 3139 times.
✓ Branch 1 taken 73 times.
3212 for (int j = 0; j < frame_height; j += 1)
1218
2/2
✓ Branch 0 taken 301344 times.
✓ Branch 1 taken 3139 times.
304483 for (int i = 0; i < frame_width; i += 1)
1219 301344 mean += (gint64) elanspi_lookup_pixel_with_rotation (self, image_copy, j, i);
1220
1221 73 mean /= (frame_width * frame_height);
1222
1223
2/2
✓ Branch 0 taken 3139 times.
✓ Branch 1 taken 73 times.
3212 for (int j = 0; j < frame_height; j += 1)
1224
2/2
✓ Branch 0 taken 301344 times.
✓ Branch 1 taken 3139 times.
304483 for (int i = 0; i < frame_width; i += 1)
1225 {
1226 301344 gint64 k = (gint64) elanspi_lookup_pixel_with_rotation (self, image_copy, j, i) - mean;
1227 301344 sq_stddev += k * k;
1228 }
1229
1230 73 sq_stddev /= (frame_width * frame_height);
1231
1232
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 44 times.
73 if (invalid_percent < ELANSPI_MAX_REAL_INVALID_PERCENT)
1233 is_fp += 1;
1234
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 2 times.
29 if (invalid_percent > ELANSPI_MIN_EMPTY_INVALID_PERCENT)
1235 27 is_empty += 1;
1236
1237
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 33 times.
73 if (sq_stddev > ELANSPI_MIN_REAL_STDDEV)
1238 40 is_fp += 1;
1239
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 46 times.
73 if (sq_stddev < ELANSPI_MAX_EMPTY_STDDEV)
1240 27 is_empty += 1;
1241
1242 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);
1243
1244
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 46 times.
73 if (is_fp > is_empty)
1245 return ELANSPI_GUESS_FINGERPRINT;
1246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 else if (is_empty > is_fp)
1247 return ELANSPI_GUESS_EMPTY;
1248 else
1249 return ELANSPI_GUESS_UNKNOWN;
1250 }
1251
1252 /* returns TRUE when the waiting is complete */
1253 static gboolean
1254 49 elanspi_check_waitupdown_done (FpiDeviceElanSpi *self, enum elanspi_guess_result target)
1255 {
1256 49 enum elanspi_guess_result guess = elanspi_guess_image (self, self->last_image);
1257
1258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
49 if (guess == ELANSPI_GUESS_UNKNOWN)
1259 return FALSE;
1260
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 45 times.
49 if (guess == target)
1261 {
1262 4 self->finger_wait_debounce += 1;
1263 4 return self->finger_wait_debounce == ELANSPI_MIN_FRAMES_DEBOUNCE;
1264 }
1265 else
1266 {
1267 45 self->finger_wait_debounce = 0;
1268 45 return FALSE;
1269 }
1270 }
1271
1272 static int
1273 951265 cmp_u16 (const void *a, const void *b)
1274 {
1275 951265 return (int) (*(guint16 *) a - *(guint16 *) b);
1276 }
1277
1278 static void
1279 23 elanspi_process_frame (FpiDeviceElanSpi *self, const guint16 *data_in, guint8 *data_out)
1280 23 {
1281 23 size_t frame_size = self->frame_width * self->frame_height;
1282 23 guint16 data_in_sorted[frame_size];
1283
1284
2/2
✓ Branch 0 taken 989 times.
✓ Branch 1 taken 23 times.
1012 for (int i = 0, offset = 0; i < self->frame_height; i += 1)
1285
2/2
✓ Branch 0 taken 94944 times.
✓ Branch 1 taken 989 times.
95933 for (int j = 0; j < self->frame_width; j += 1)
1286 94944 data_in_sorted[offset++] = elanspi_lookup_pixel_with_rotation (self, data_in, i, j);
1287
1288 23 qsort (data_in_sorted, frame_size, 2, cmp_u16);
1289 23 guint16 lvl0 = data_in_sorted[0];
1290 23 guint16 lvl1 = data_in_sorted[frame_size * 3 / 10];
1291 23 guint16 lvl2 = data_in_sorted[frame_size * 65 / 100];
1292 23 guint16 lvl3 = data_in_sorted[frame_size - 1];
1293
1294 23 lvl1 = MAX (lvl1, lvl0 + 1);
1295 23 lvl2 = MAX (lvl2, lvl1 + 1);
1296 23 lvl3 = MAX (lvl3, lvl2 + 1);
1297
1298
2/2
✓ Branch 0 taken 989 times.
✓ Branch 1 taken 23 times.
1012 for (int i = 0; i < self->frame_height; i += 1)
1299 {
1300
2/2
✓ Branch 0 taken 94944 times.
✓ Branch 1 taken 989 times.
95933 for (int j = 0; j < self->frame_width; j += 1)
1301 {
1302 94944 guint16 px = elanspi_lookup_pixel_with_rotation (self, data_in, i, j);
1303
1/2
✓ Branch 0 taken 94944 times.
✗ Branch 1 not taken.
94944 if (px < lvl0)
1304 {
1305 px = 0;
1306 }
1307
1/2
✓ Branch 0 taken 94944 times.
✗ Branch 1 not taken.
94944 else if (px > lvl3)
1308 {
1309 px = 255;
1310 }
1311 else
1312 {
1313
2/2
✓ Branch 0 taken 28460 times.
✓ Branch 1 taken 66484 times.
94944 if (lvl0 <= px && px < lvl1)
1314 28460 px = (px - lvl0) * 99 / (lvl1 - lvl0);
1315
2/2
✓ Branch 0 taken 33232 times.
✓ Branch 1 taken 33252 times.
66484 else if (lvl1 <= px && px < lvl2)
1316 33232 px = 99 + ((px - lvl1) * 56 / (lvl2 - lvl1));
1317 else /* (lvl2 <= px && px <= lvl3) */
1318 33252 px = 155 + ((px - lvl2) * 100 / (lvl3 - lvl2));
1319 }
1320 94944 *data_out = px;
1321 94944 data_out += 1;
1322 }
1323 }
1324 23 }
1325
1326 static unsigned char
1327 152172653 elanspi_fp_assembling_get_pixel (struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, unsigned int y)
1328 {
1329 152172653 return frame->data[y * ctx->frame_width + x];
1330 }
1331
1332 static void
1333 1 elanspi_fp_frame_stitch_and_submit (FpiDeviceElanSpi *self)
1334 {
1335 2 g_autoptr(FpImage) img = NULL;
1336
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_autoptr(FpImage) scaled = NULL;
1337 1 struct fpi_frame_asmbl_ctx assembling_ctx = {
1338 1 .image_width = (self->frame_width * 3) / 2,
1339
1340 1 .frame_width = self->frame_width,
1341 1 .frame_height = self->frame_height,
1342
1343 .get_pixel = elanspi_fp_assembling_get_pixel,
1344 };
1345
1346 /* stitch image */
1347 1 GSList *frame_start = g_slist_nth (self->fp_frame_list, ELANSPI_SWIPE_FRAMES_DISCARD);
1348
1349 1 fpi_do_movement_estimation (&assembling_ctx, frame_start);
1350 1 img = fpi_assemble_frames (&assembling_ctx, frame_start);
1351 1 scaled = fpi_image_resize (img, 2, 2);
1352
1353 1 scaled->flags |= FPI_IMAGE_PARTIAL | FPI_IMAGE_COLORS_INVERTED;
1354
1355 /* submit image */
1356 1 fpi_image_device_image_captured (FP_IMAGE_DEVICE (self), g_steal_pointer (&scaled));
1357
1358 /* clean out frame data */
1359
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 g_slist_free_full (g_steal_pointer (&self->fp_frame_list), g_free);
1360 1 }
1361
1362 static gint64
1363 22 elanspi_get_frame_diff_stddev_sq (FpiDeviceElanSpi *self, guint16 *frame1, guint16 *frame2)
1364 {
1365 22 gint64 mean = 0;
1366 22 gint64 sq_stddev = 0;
1367
1368
2/2
✓ Branch 0 taken 202752 times.
✓ Branch 1 taken 22 times.
202774 for (int j = 0; j < (self->sensor_height * self->sensor_width); j += 1)
1369 202752 mean += abs ((int) frame1[j] - (int) frame2[j]);
1370
1371
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
22 g_assert (self->sensor_height && self->sensor_width); /* make clang happy about div0 */
1372 22 mean /= (self->sensor_height * self->sensor_width);
1373
1374
2/2
✓ Branch 0 taken 202752 times.
✓ Branch 1 taken 22 times.
202774 for (int j = 0; j < (self->sensor_height * self->sensor_width); j += 1)
1375 {
1376 202752 gint64 k = abs ((int) frame1[j] - (int) frame2[j]) - mean;
1377 202752 sq_stddev += k * k;
1378 }
1379
1380 22 sq_stddev /= (self->sensor_height * self->sensor_width);
1381
1382 22 return sq_stddev;
1383 }
1384
1385 static void
1386 24 elanspi_fp_frame_handler (FpiSsm *ssm, FpiDeviceElanSpi *self)
1387 {
1388 48 g_autofree struct fpi_frame *this_frame = NULL;
1389
1390
1/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
24 switch (elanspi_guess_image (self, self->last_image))
1391 {
1392 case ELANSPI_GUESS_UNKNOWN:
1393 fp_dbg ("<fp_frame> unknown, ignore...");
1394 break;
1395
1396 case ELANSPI_GUESS_EMPTY:
1397 self->fp_empty_counter += 1;
1398 fp_dbg ("<fp_frame> got empty");
1399 if (self->fp_empty_counter > 1)
1400 {
1401 fp_dbg ("<fp_frame> have enough debounce");
1402 if (g_slist_length (self->fp_frame_list) >= ELANSPI_MIN_FRAMES_SWIPE)
1403 {
1404 fp_dbg ("<fp_frame> have enough frames, submitting");
1405 elanspi_fp_frame_stitch_and_submit (self);
1406 }
1407 else
1408 {
1409 fp_dbg ("<fp_frame> not enough frames, reporting short swipe");
1410 fpi_image_device_retry_scan (FP_IMAGE_DEVICE (self), FP_DEVICE_RETRY_TOO_SHORT);
1411 }
1412 goto finish_capture;
1413 }
1414 break;
1415
1416 24 case ELANSPI_GUESS_FINGERPRINT:
1417
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
24 if (self->fp_empty_counter && self->fp_frame_list)
1418 {
1419 if (self->fp_empty_counter < 1)
1420 {
1421 fp_dbg ("<fp_frame> possible bounced fp");
1422 break;
1423 }
1424 else
1425 {
1426 fp_dbg ("<fp_frame> too many empties, clearing list");
1427 g_slist_free_full (g_steal_pointer (&self->fp_frame_list), g_free);
1428 self->fp_empty_counter = 0;
1429 }
1430 }
1431
1432
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 23 times.
24 if (g_slist_length (self->fp_frame_list) > ELANSPI_MAX_FRAMES_SWIPE)
1433 {
1434 1 fp_dbg ("<fp_frame> have enough frames, exiting now");
1435 1 elanspi_fp_frame_stitch_and_submit (self);
1436 1 goto finish_capture;
1437 }
1438
1439 /* append image */
1440 23 this_frame = g_malloc0 (self->sensor_height * self->sensor_width + sizeof (struct fpi_frame));
1441 23 elanspi_correct_with_bg (self, self->last_image);
1442 23 elanspi_process_frame (self, self->last_image, this_frame->data);
1443
1444
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 1 times.
23 if (self->fp_frame_list)
1445 {
1446 22 gint difference = elanspi_get_frame_diff_stddev_sq (self, self->last_image, self->prev_frame_image);
1447 22 fp_dbg ("<fp_frame> diff = %d", difference);
1448
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 21 times.
22 if (difference < ELANSPI_MIN_FRAME_TO_FRAME_DIFF)
1449 {
1450 1 fp_dbg ("<fp_frame> ignoring b.c. difference is too small");
1451 1 break;
1452 }
1453 }
1454 22 self->fp_frame_list = g_slist_prepend (self->fp_frame_list, g_steal_pointer (&this_frame));
1455 22 memcpy (self->prev_frame_image, self->last_image, self->sensor_height * self->sensor_width * 2);
1456 22 break;
1457 }
1458
1459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (self->sensor_id == 0xe)
1460 fpi_ssm_jump_to_state_delayed (ssm, ELANSPI_FPCAPT_FP_CAPTURE, ELANSPI_HV_SENSOR_FRAME_DELAY);
1461 else
1462 23 fpi_ssm_jump_to_state (ssm, ELANSPI_FPCAPT_FP_CAPTURE);
1463
1464 return;
1465
1466 1 finish_capture:
1467 /* prepare for wait up */
1468 1 self->finger_wait_debounce = 0;
1469 1 fpi_ssm_jump_to_state (ssm, ELANSPI_FPCAPT_WAITUP_CAPTURE);
1470 1 return;
1471
1472 }
1473
1474 static void
1475 147 elanspi_fp_capture_ssm_handler (FpiSsm *ssm, FpDevice *dev)
1476 {
1477 147 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1478 147 FpiSsm *chld = NULL;
1479
1480
5/6
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 73 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
147 switch (fpi_ssm_get_cur_state (ssm))
1481 {
1482 1 case ELANSPI_FPCAPT_INIT:
1483 1 self->finger_wait_debounce = 0;
1484
1485 1 fpi_ssm_next_state (ssm);
1486 1 return;
1487
1488 73 case ELANSPI_FPCAPT_WAITDOWN_CAPTURE:
1489 case ELANSPI_FPCAPT_WAITUP_CAPTURE:
1490 case ELANSPI_FPCAPT_FP_CAPTURE:
1491 /* check if we are deactivating */
1492
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 if (self->deactivating)
1493 {
1494 fp_dbg ("<capture> got deactivate; exiting");
1495
1496 self->deactivating = FALSE;
1497 fpi_ssm_mark_completed (ssm);
1498
1499 /* mark deactivate done */
1500 fpi_image_device_deactivate_complete (FP_IMAGE_DEVICE (dev), NULL);
1501
1502 return;
1503 }
1504 /* if sensor is hv */
1505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 if (self->sensor_id == 0xe)
1506 chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES);
1507 else
1508 73 chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES);
1509 73 fpi_ssm_silence_debug (chld);
1510 73 fpi_ssm_start_subsm (ssm, chld);
1511 73 return;
1512
1513 27 case ELANSPI_FPCAPT_WAITDOWN_PROCESS:
1514
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 1 times.
27 if (!elanspi_check_waitupdown_done (self, ELANSPI_GUESS_FINGERPRINT))
1515 {
1516 /* take another image */
1517 26 fpi_ssm_jump_to_state (ssm, ELANSPI_FPCAPT_WAITDOWN_CAPTURE);
1518 26 return;
1519 }
1520
1521 /* prepare to take actual image */
1522 1 self->finger_wait_debounce = 0;
1523 1 g_slist_free_full (g_steal_pointer (&self->fp_frame_list), g_free);
1524 1 self->fp_empty_counter = 0;
1525
1526 /* report finger status */
1527 1 fpi_image_device_report_finger_status (FP_IMAGE_DEVICE (self), TRUE);
1528
1529 /* jump */
1530 1 fpi_ssm_jump_to_state (ssm, ELANSPI_FPCAPT_FP_CAPTURE);
1531 1 return;
1532
1533 24 case ELANSPI_FPCAPT_FP_PROCESS:
1534 24 elanspi_fp_frame_handler (ssm, self);
1535 24 return;
1536
1537 22 case ELANSPI_FPCAPT_WAITUP_PROCESS:
1538
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 1 times.
22 if (!elanspi_check_waitupdown_done (self, ELANSPI_GUESS_EMPTY))
1539 {
1540 /* take another image */
1541 21 fpi_ssm_jump_to_state (ssm, ELANSPI_FPCAPT_WAITUP_CAPTURE);
1542 21 return;
1543 }
1544
1545 /* Immediately set capturing to FALSE so that when report_finger_status tries to re-start
1546 * capturing in enroll we don't hit the assert since the old SSM is about to stop. */
1547 1 self->capturing = FALSE;
1548 1 fpi_image_device_report_finger_status (FP_IMAGE_DEVICE (self), FALSE);
1549
1550 /* finish */
1551 1 fpi_ssm_mark_completed (ssm);
1552 1 return;
1553 }
1554 }
1555
1556 static void
1557 1 elanspi_open (FpImageDevice *dev)
1558 {
1559 1 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1560 1 GError *err = NULL;
1561
1562 1 G_DEBUG_HERE ();
1563
1564 1 int spi_fd = open (fpi_device_get_udev_data (FP_DEVICE (dev), FPI_DEVICE_UDEV_SUBTYPE_SPIDEV), O_RDWR);
1565
1566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (spi_fd < 0)
1567 {
1568 g_set_error (&err, G_IO_ERROR, g_io_error_from_errno (errno), "unable to open spi");
1569 fpi_image_device_open_complete (dev, err);
1570 return;
1571 }
1572
1573 1 self->spi_fd = spi_fd;
1574
1575 1 fpi_image_device_open_complete (dev, NULL);
1576 }
1577
1578 static void
1579 1 elanspi_close (FpImageDevice *dev)
1580 {
1581 1 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1582
1583
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->spi_fd >= 0)
1584 {
1585 1 close (self->spi_fd);
1586 1 self->spi_fd = -1;
1587 }
1588 1 fpi_image_device_close_complete (dev, NULL);
1589 1 }
1590
1591 static void
1592 1 elanspi_init_finish (FpiSsm *ssm, FpDevice *dev, GError *error)
1593 {
1594 1 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
1595
1596 1 G_DEBUG_HERE ();
1597 1 fpi_image_device_activate_complete (idev, error);
1598 1 }
1599
1600 static void
1601 1 elanspi_activate (FpImageDevice *dev)
1602 {
1603 1 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), elanspi_init_ssm_handler, ELANSPI_INIT_NSTATES);
1604
1605 1 fpi_ssm_start (ssm, elanspi_init_finish);
1606 1 }
1607
1608 static void
1609 1 elanspi_deactivate (FpImageDevice *dev)
1610 {
1611 1 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1612
1613
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (self->capturing)
1614 {
1615 self->deactivating = TRUE;
1616 fp_dbg ("<deactivate> waiting capture to stop");
1617 }
1618 else
1619 {
1620 1 fpi_image_device_deactivate_complete (dev, NULL);
1621 }
1622 1 }
1623
1624 static void
1625 1 elanspi_fp_capture_finish (FpiSsm *ssm, FpDevice *dev, GError *error)
1626 {
1627 1 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
1628 1 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1629
1630 1 self->capturing = FALSE;
1631
1632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (self->deactivating)
1633 {
1634 /* finish deactivate */
1635 if (error)
1636 g_error_free (error);
1637 self->deactivating = FALSE;
1638 fpi_image_device_deactivate_complete (idev, NULL);
1639 return;
1640 }
1641
1642 /* if there was an error, report it */
1643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (error)
1644 fpi_image_device_session_error (idev, error);
1645 }
1646
1647 static void
1648 8 elanspi_change_state (FpImageDevice *dev, FpiImageDeviceState state)
1649 {
1650 8 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (dev);
1651
1652
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
1653 {
1654
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_assert (self->capturing == FALSE);
1655
1656 /* start capturer */
1657 1 self->capturing = TRUE;
1658 1 fpi_ssm_start (fpi_ssm_new (FP_DEVICE (dev),
1659 elanspi_fp_capture_ssm_handler,
1660 ELANSPI_FPCAPT_NSTATES),
1661 elanspi_fp_capture_finish);
1662
1663 1 fp_dbg ("<change_state> started capturer");
1664 }
1665 else
1666 {
1667 /* todo: other states? */
1668 8 }
1669 8 }
1670
1671 static void
1672 1 fpi_device_elanspi_init (FpiDeviceElanSpi *self)
1673 {
1674 1 self->spi_fd = -1;
1675 1 self->sensor_id = 0xff;
1676 1 }
1677
1678 static void
1679 1 fpi_device_elanspi_finalize (GObject *this)
1680 {
1681 1 FpiDeviceElanSpi *self = FPI_DEVICE_ELANSPI (this);
1682
1683
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_clear_pointer (&self->bg_image, g_free);
1684
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_clear_pointer (&self->last_image, g_free);
1685
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_clear_pointer (&self->prev_frame_image, g_free);
1686 1 g_slist_free_full (g_steal_pointer (&self->fp_frame_list), g_free);
1687
1688 1 G_OBJECT_CLASS (fpi_device_elanspi_parent_class)->finalize (this);
1689 1 }
1690
1691 static void
1692 117 fpi_device_elanspi_class_init (FpiDeviceElanSpiClass *klass)
1693 {
1694 117 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
1695 117 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
1696
1697 117 dev_class->id = "elanspi";
1698 117 dev_class->full_name = "ElanTech Embedded Fingerprint Sensor";
1699 117 dev_class->type = FP_DEVICE_TYPE_UDEV;
1700 117 dev_class->id_table = elanspi_id_table;
1701 117 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
1702 117 dev_class->nr_enroll_stages = 7; /* these sensors are very hit or miss, may as well record a few extras */
1703
1704 117 img_class->bz3_threshold = 24;
1705 117 img_class->img_open = elanspi_open;
1706 117 img_class->activate = elanspi_activate;
1707 117 img_class->deactivate = elanspi_deactivate;
1708 117 img_class->change_state = elanspi_change_state;
1709 117 img_class->img_close = elanspi_close;
1710
1711 117 G_OBJECT_CLASS (klass)->finalize = fpi_device_elanspi_finalize;
1712 }
1713