GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 78.6% 309 / 0 / 393
Functions: 100.0% 27 / 0 / 27
Branches: 54.7% 75 / 0 / 137

libfprint/drivers/upektc_img.c
Line Branch Exec Source
1 /*
2 * UPEK TouchChip driver for libfprint
3 * Copyright (C) 2013 Vasily Khoruzhick <anarsoul@gmail.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #define FP_COMPONENT "upektc_img"
21
22 #include "drivers_api.h"
23 #include "upek_proto.h"
24 #include "upektc_img.h"
25
26 static void start_capture (FpImageDevice *dev);
27 static void start_deactivation (FpImageDevice *dev);
28
29 #define EP_IN (1 | FPI_USB_ENDPOINT_IN)
30 #define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
31 #define CTRL_TIMEOUT 4000
32 #define BULK_TIMEOUT 4000
33
34 #define MAX_CMD_SIZE 64
35 #define MAX_RESPONSE_SIZE 2052
36 #define SHORT_RESPONSE_SIZE 64
37
38 struct _FpiDeviceUpektcImg
39 {
40 FpImageDevice parent;
41
42 unsigned char cmd[MAX_CMD_SIZE];
43 unsigned char response[MAX_RESPONSE_SIZE];
44 unsigned char *image_bits;
45 unsigned char seq;
46 size_t expected_image_size;
47 size_t image_size;
48 size_t response_rest;
49 gboolean area_sensor;
50 gboolean deactivating;
51 };
52 G_DECLARE_FINAL_TYPE (FpiDeviceUpektcImg, fpi_device_upektc_img, FPI,
53 DEVICE_UPEKTC_IMG, FpImageDevice);
54
4/6
fpi_device_upektc_img_class_intern_init:
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 125 times.
fpi_device_upektc_img_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 (FpiDeviceUpektcImg, fpi_device_upektc_img, FP_TYPE_IMAGE_DEVICE);
55
56 /****** HELPERS ******/
57
58 static void
59 70 upektc_img_cmd_fix_seq (unsigned char *cmd_buf, unsigned char seq)
60 {
61 70 uint8_t byte;
62
63 70 byte = cmd_buf[5];
64 70 byte &= 0x0f;
65 70 byte |= (seq << 4);
66 70 cmd_buf[5] = byte;
67 }
68
69 static void
70 70 upektc_img_cmd_update_crc (unsigned char *cmd_buf, size_t size)
71 {
72 /* CRC does not cover Ciao prefix (4 bytes) and CRC location (2 bytes) */
73 70 uint16_t crc = udf_crc (cmd_buf + 4, size - 6);
74
75 70 cmd_buf[size - 2] = (crc & 0x00ff);
76 70 cmd_buf[size - 1] = (crc & 0xff00) >> 8;
77 70 }
78
79 FP_GNUC_ACCESS (read_only, 3, 4)
80 static void
81 70 upektc_img_submit_req (FpiSsm *ssm,
82 FpImageDevice *dev,
83 const unsigned char *buf,
84 size_t buf_size,
85 unsigned char seq,
86 FpiUsbTransferCallback cb)
87 {
88 70 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
89 70 FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
90
91
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 7 taken 70 times.
70 BUG_ON (buf_size > MAX_CMD_SIZE);
92
93 70 memcpy (self->cmd, buf, buf_size);
94 70 upektc_img_cmd_fix_seq (self->cmd, seq);
95 70 upektc_img_cmd_update_crc (self->cmd, buf_size);
96
97 70 fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, self->cmd, buf_size,
98 NULL);
99 70 transfer->ssm = ssm;
100 70 transfer->short_is_error = TRUE;
101 70 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, cb, NULL);
102 70 }
103
104 static void
105 132 upektc_img_read_data (FpiSsm *ssm,
106 FpImageDevice *dev,
107 size_t buf_size,
108 size_t buf_offset,
109 FpiUsbTransferCallback cb)
110 {
111 132 FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
112 132 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
113
114
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 7 taken 132 times.
132 BUG_ON (buf_offset + buf_size > MAX_RESPONSE_SIZE);
115
116 132 fpi_usb_transfer_fill_bulk_full (transfer, EP_IN,
117 132 self->response + buf_offset, buf_size,
118 NULL);
119 132 transfer->ssm = ssm;
120 132 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL, cb, NULL);
121 132 }
122
123 /****** CAPTURE ******/
124
125 enum capture_states {
126 CAPTURE_INIT_CAPTURE,
127 CAPTURE_READ_DATA,
128 CAPTURE_READ_DATA_TERM,
129 CAPTURE_ACK_00_28,
130 CAPTURE_ACK_08,
131 CAPTURE_ACK_FRAME,
132 CAPTURE_ACK_00_28_TERM,
133 CAPTURE_NUM_STATES,
134 };
135
136 static void
137 60 capture_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device,
138 gpointer user_data, GError *error)
139 {
140
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 60 times.
60 if (error)
141 {
142 fpi_ssm_mark_failed (transfer->ssm, error);
143 return;
144 }
145
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 9 taken 60 times.
60 switch (fpi_ssm_get_cur_state (transfer->ssm))
146 {
147 case CAPTURE_ACK_00_28_TERM:
148 fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA_TERM);
149 break;
150
151 60 default:
152 60 fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
153 60 break;
154 }
155 }
156
157 static int
158 54 upektc_img_process_image_frame (unsigned char *image_buf, size_t image_buf_len,
159 unsigned char *cmd_res, size_t cmd_res_len)
160 {
161 54 int offset = 8;
162 54 int len = ((cmd_res[5] & 0x0f) << 8) | (cmd_res[6]);
163
164 54 len -= 1;
165
2/2
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 4 taken 52 times.
54 if (cmd_res[7] == 0x2c)
166 {
167 2 len -= 10;
168 2 offset += 10;
169 }
170
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 52 times.
54 if (cmd_res[7] == 0x20)
171 2 len -= 4;
172
173
1/2
✓ Branch 6 → 7 taken 54 times.
✗ Branch 6 → 9 not taken.
54 if (len <= 0 ||
174
2/4
✓ Branch 7 → 8 taken 54 times.
✗ Branch 7 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 11 taken 54 times.
54 (size_t) offset + (size_t) len > cmd_res_len ||
175 (size_t) len > image_buf_len)
176 {
177 fp_dbg ("Invalid image frame length %d (offset %d, source %zu, dest %zu)",
178 len, offset, cmd_res_len, image_buf_len);
179 return 0;
180 }
181
182 54 memcpy (image_buf, cmd_res + offset, len);
183
184 54 return len;
185 }
186
187 static void
188 118 capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
189 gpointer user_data, GError *error)
190 {
191 118 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
192
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 118 times.
118 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_GET_CLASS (dev);
193 118 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
194 118 unsigned char *data = self->response;
195 118 FpImage *img;
196 118 size_t response_size;
197
198
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 118 times.
118 if (error)
199 {
200 fp_dbg ("request is not completed, %s", error->message);
201 fpi_ssm_mark_failed (transfer->ssm, error);
202 return;
203 }
204
205
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 10 taken 118 times.
118 if (self->deactivating)
206 {
207 fp_dbg ("Deactivate requested");
208 fpi_ssm_mark_completed (transfer->ssm);
209 return;
210 }
211
212 118 fp_dbg ("request completed, len: %.4x", (gint) transfer->actual_length);
213
2/2
✓ Branch 11 → 12 taken 4 times.
✓ Branch 11 → 15 taken 114 times.
118 if (transfer->actual_length == 0)
214 {
215 4 fpi_ssm_jump_to_state (transfer->ssm,
216 fpi_ssm_get_cur_state (transfer->ssm));
217 4 return;
218 }
219
220
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 20 taken 114 times.
114 if (fpi_ssm_get_cur_state (transfer->ssm) == CAPTURE_READ_DATA_TERM)
221 {
222 fp_dbg ("Terminating SSM");
223 fpi_ssm_mark_completed (transfer->ssm);
224 return;
225 }
226
227
2/2
✓ Branch 20 → 21 taken 60 times.
✓ Branch 20 → 30 taken 54 times.
114 if (!self->response_rest)
228 {
229 60 response_size = ((data[5] & 0x0f) << 8) + data[6];
230 60 response_size += 9; /* 7 bytes for header, 2 for CRC */
231
2/2
✓ Branch 21 → 22 taken 54 times.
✓ Branch 21 → 30 taken 6 times.
60 if (response_size > transfer->actual_length)
232 {
233 54 fp_dbg ("response_size is %lu, actual_length is %d",
234 (gulong) response_size, (gint) transfer->actual_length);
235 54 fp_dbg ("Waiting for rest of transfer");
236
1/2
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 28 taken 54 times.
54 BUG_ON (self->response_rest);
237 54 self->response_rest = response_size - transfer->actual_length;
238 54 fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
239 54 return;
240 }
241 }
242 60 self->response_rest = 0;
243
244
2/3
✓ Branch 30 → 31 taken 59 times.
✓ Branch 30 → 89 taken 1 time.
✗ Branch 30 → 91 not taken.
60 switch (data[4])
245 {
246 59 case 0x00:
247
4/5
✓ Branch 31 → 32 taken 5 times.
✓ Branch 31 → 69 taken 2 times.
✓ Branch 31 → 70 taken 50 times.
✓ Branch 31 → 73 taken 2 times.
✗ Branch 31 → 85 not taken.
59 switch (data[7])
248 {
249 /* No finger */
250 5 case 0x28:
251 5 fp_dbg ("18th byte is %.2x", data[18]);
252
3/7
✓ Branch 33 → 34 taken 2 times.
✓ Branch 33 → 36 taken 1 time.
✓ Branch 33 → 41 taken 2 times.
✗ Branch 33 → 44 not taken.
✗ Branch 33 → 47 not taken.
✗ Branch 33 → 54 not taken.
✗ Branch 33 → 61 not taken.
5 switch (data[18])
253 {
254 2 case 0x0c:
255 /* no finger */
256 2 fpi_ssm_jump_to_state (transfer->ssm,
257 CAPTURE_ACK_00_28);
258 2 break;
259
260 1 case 0x13:
261 /* finger is present keep your finger on reader */
262 1 fpi_device_report_finger_status_changes (device,
263 FP_FINGER_STATUS_NEEDED,
264 FP_FINGER_STATUS_NONE);
265 2 fpi_ssm_jump_to_state (transfer->ssm,
266
1/2
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 1 time.
1 self->area_sensor ?
267 CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
268 1 break;
269
270 2 case 0x00:
271 /* finger is present! */
272 2 fpi_device_report_finger_status_changes (device,
273 FP_FINGER_STATUS_PRESENT,
274 FP_FINGER_STATUS_NONE);
275 2 fpi_ssm_jump_to_state (transfer->ssm,
276 CAPTURE_ACK_00_28);
277 2 break;
278
279 case 0x01:
280 /* no finger! */
281 fpi_device_report_finger_status_changes (device,
282 FP_FINGER_STATUS_NONE,
283 FP_FINGER_STATUS_PRESENT);
284 fpi_ssm_jump_to_state (transfer->ssm,
285 CAPTURE_ACK_00_28);
286 break;
287
288 case 0x1e:
289 /* short scan */
290 fp_err ("short scan, aborting");
291 fpi_image_device_retry_scan (dev,
292 FP_DEVICE_RETRY_TOO_SHORT);
293 fpi_image_device_report_finger_status (dev,
294 FALSE);
295 fpi_ssm_jump_to_state (transfer->ssm,
296 self->area_sensor ?
297 CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
298 break;
299
300 case 0x1d:
301 /* too much horizontal movement */
302 fp_err ("too much horizontal movement, aborting");
303 fpi_image_device_retry_scan (dev,
304 FP_DEVICE_RETRY_CENTER_FINGER);
305 fpi_image_device_report_finger_status (dev,
306 FALSE);
307 fpi_ssm_jump_to_state (transfer->ssm,
308 self->area_sensor ?
309 CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
310 break;
311
312 default:
313 /* some error happened, cancel scan */
314 fp_err ("something bad happened, stop scan");
315 fpi_image_device_retry_scan (dev,
316 FP_DEVICE_RETRY);
317 fpi_image_device_report_finger_status (dev,
318 FALSE);
319 fpi_ssm_jump_to_state (transfer->ssm,
320 self->area_sensor ?
321 CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
322 break;
323 }
324 break;
325
326 /* Image frame with additional info */
327 2 case 0x2c:
328 2 fpi_image_device_report_finger_status (dev,
329 TRUE);
330
331 /* Plain image frame */
332 52 case 0x24:
333 104 self->image_size +=
334 104 upektc_img_process_image_frame (self->image_bits + self->image_size,
335 52 (self->expected_image_size * 2) - self->image_size,
336 data, MAX_RESPONSE_SIZE);
337 52 fpi_ssm_jump_to_state (transfer->ssm,
338 CAPTURE_ACK_FRAME);
339 52 break;
340
341 /* Last image frame */
342 2 case 0x20:
343 4 self->image_size +=
344 4 upektc_img_process_image_frame (self->image_bits + self->image_size,
345 2 (self->expected_image_size * 2) - self->image_size,
346 data, MAX_RESPONSE_SIZE);
347
1/2
✗ Branch 74 → 75 not taken.
✓ Branch 74 → 79 taken 2 times.
2 if (self->image_size != self->expected_image_size)
348 {
349 fp_err ("Image size mismatch: got %zu, expected %zu",
350 self->image_size, self->expected_image_size);
351 fpi_ssm_mark_failed (transfer->ssm,
352 fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
353 return;
354 }
355 2 fp_dbg ("Image size is %lu",
356 (gulong) self->image_size);
357 2 img = fp_image_new (img_class->img_width, img_class->img_height);
358 2 img->flags |= FPI_IMAGE_PARTIAL;
359 2 memcpy (img->data, self->image_bits,
360 self->image_size);
361 2 fpi_image_device_image_captured (dev, img);
362 2 fpi_image_device_report_finger_status (dev,
363 FALSE);
364 2 fpi_ssm_mark_completed (transfer->ssm);
365 2 break;
366
367 default:
368 fp_err ("Unknown response!");
369 fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
370 break;
371 }
372 break;
373
374 1 case 0x08:
375 1 fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_ACK_08);
376 1 break;
377
378 default:
379 fp_err ("Not handled response!");
380 fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
381 }
382 }
383
384 static void
385 178 capture_run_state (FpiSsm *ssm, FpDevice *_dev)
386 {
387 178 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
388 178 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
389
390
5/6
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 8 taken 118 times.
✓ Branch 3 → 11 taken 5 times.
✓ Branch 3 → 13 taken 1 time.
✓ Branch 3 → 15 taken 52 times.
✗ Branch 3 → 17 not taken.
178 switch (fpi_ssm_get_cur_state (ssm))
391 {
392 2 case CAPTURE_INIT_CAPTURE:
393
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 1 time.
2 if (self->area_sensor)
394 1 upektc_img_submit_req (ssm, dev, upek2020_init_capture_press, sizeof (upek2020_init_capture_press),
395 self->seq, capture_reqs_cb);
396 else
397 1 upektc_img_submit_req (ssm, dev, upek2020_init_capture, sizeof (upek2020_init_capture),
398 self->seq, capture_reqs_cb);
399 2 self->seq++;
400 2 break;
401
402 118 case CAPTURE_READ_DATA:
403 case CAPTURE_READ_DATA_TERM:
404
2/2
✓ Branch 8 → 9 taken 64 times.
✓ Branch 8 → 10 taken 54 times.
118 if (!self->response_rest)
405 64 upektc_img_read_data (ssm, dev, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb);
406 else
407 54 upektc_img_read_data (ssm, dev, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE,
408 SHORT_RESPONSE_SIZE, capture_read_data_cb);
409 break;
410
411 5 case CAPTURE_ACK_00_28:
412 case CAPTURE_ACK_00_28_TERM:
413 5 upektc_img_submit_req (ssm, dev, upek2020_ack_00_28, sizeof (upek2020_ack_00_28),
414 self->seq, capture_reqs_cb);
415 5 self->seq++;
416 5 break;
417
418 1 case CAPTURE_ACK_08:
419 1 upektc_img_submit_req (ssm, dev, upek2020_ack_08, sizeof (upek2020_ack_08),
420 0, capture_reqs_cb);
421 1 break;
422
423 52 case CAPTURE_ACK_FRAME:
424 52 upektc_img_submit_req (ssm, dev, upek2020_ack_frame, sizeof (upek2020_ack_frame),
425 self->seq, capture_reqs_cb);
426 52 self->seq++;
427 52 break;
428 }
429 178 ;
430 178 }
431
432 static void
433 2 capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error_arg)
434 {
435 4 g_autoptr(GError) error = error_arg;
436 2 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
437 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
438
439 /* Note: We assume that the error is a cancellation in the deactivation case */
440
1/2
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 4 not taken.
2 if (self->deactivating)
441 2 start_deactivation (dev);
442 else if (error)
443 fpi_image_device_session_error (dev, g_steal_pointer (&error));
444 else
445 start_capture (dev);
446 2 }
447
448 static void
449 2 start_capture (FpImageDevice *dev)
450 {
451 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
452 2 FpiSsm *ssm;
453
454 2 self->image_size = 0;
455
456 2 ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state,
457 CAPTURE_NUM_STATES);
458 2 fpi_ssm_start (ssm, capture_sm_complete);
459 2 }
460
461 /****** INITIALIZATION/DEINITIALIZATION ******/
462
463 enum deactivate_states {
464 DEACTIVATE_DEINIT,
465 DEACTIVATE_READ_DEINIT_DATA,
466 DEACTIVATE_NUM_STATES,
467 };
468
469 static void
470 2 deactivate_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device,
471 gpointer user_data, GError *error)
472 {
473
1/2
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 4 not taken.
2 if (!error)
474 2 fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
475 else
476 fpi_ssm_mark_failed (transfer->ssm, error);
477 2 }
478
479 /* TODO: process response properly */
480 static void
481 2 deactivate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
482 gpointer user_data, GError *error)
483 {
484
1/2
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 4 not taken.
2 if (!error)
485 2 fpi_ssm_mark_completed (transfer->ssm);
486 else
487 fpi_ssm_mark_failed (transfer->ssm, error);
488 2 }
489
490 static void
491 4 deactivate_run_state (FpiSsm *ssm, FpDevice *_dev)
492 {
493 4 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
494 4 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
495
496
2/3
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 6 taken 2 times.
✗ Branch 3 → 8 not taken.
4 switch (fpi_ssm_get_cur_state (ssm))
497 {
498 2 case DEACTIVATE_DEINIT:
499 2 upektc_img_submit_req (ssm, dev, upek2020_deinit, sizeof (upek2020_deinit),
500 self->seq, deactivate_reqs_cb);
501 2 self->seq++;
502 2 break;
503
504 2 case DEACTIVATE_READ_DEINIT_DATA:
505 2 upektc_img_read_data (ssm, dev, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb);
506 2 break;
507 }
508 4 ;
509 4 }
510
511 static void
512 2 deactivate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
513 {
514 2 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
515 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
516
517 2 fp_dbg ("Deactivate completed");
518
519
1/2
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 5 not taken.
2 g_clear_pointer (&self->image_bits, g_free);
520 2 self->deactivating = FALSE;
521 2 fpi_image_device_deactivate_complete (dev, error);
522 2 }
523
524 static void
525 2 start_deactivation (FpImageDevice *dev)
526 {
527 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
528 2 FpiSsm *ssm;
529
530 2 self->image_size = 0;
531
532 2 ssm = fpi_ssm_new (FP_DEVICE (dev), deactivate_run_state,
533 DEACTIVATE_NUM_STATES);
534 2 fpi_ssm_start (ssm, deactivate_sm_complete);
535 2 }
536
537 enum activate_states {
538 ACTIVATE_CONTROL_REQ_1,
539 ACTIVATE_READ_CTRL_RESP_1,
540 ACTIVATE_INIT_1,
541 ACTIVATE_READ_INIT_1_RESP,
542 ACTIVATE_INIT_2,
543 ACTIVATE_READ_INIT_2_RESP,
544 ACTIVATE_CONTROL_REQ_2,
545 ACTIVATE_READ_CTRL_RESP_2,
546 ACTIVATE_INIT_3,
547 ACTIVATE_READ_INIT_3_RESP,
548 ACTIVATE_INIT_4,
549 ACTIVATE_READ_INIT_4_RESP,
550 ACTIVATE_NUM_STATES,
551 };
552
553 static void
554 8 init_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device,
555 gpointer user_data, GError *error)
556 {
557
1/2
✓ Branch 2 → 3 taken 8 times.
✗ Branch 2 → 4 not taken.
8 if (!error)
558 8 fpi_ssm_next_state (transfer->ssm);
559 else
560 fpi_ssm_mark_failed (transfer->ssm, error);
561 8 }
562
563 static void
564 12 init_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
565 gpointer user_data, GError *error)
566 {
567 12 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
568 12 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
569 12 unsigned char *data = self->response;
570
571
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 12 times.
12 if (error)
572 {
573 fpi_ssm_mark_failed (transfer->ssm, error);
574 return;
575 }
576
577
3/4
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 46 taken 10 times.
✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 46 not taken.
12 if (data[12] == 0x06 && data[13] == 0x14) /* if get_info */
578 {
579
2/6
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 14 not taken.
✗ Branch 7 → 20 not taken.
✓ Branch 7 → 26 taken 1 time.
✗ Branch 7 → 32 not taken.
✗ Branch 7 → 38 not taken.
2 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_GET_CLASS (dev);
580 2 uint16_t width = (data[51] << 8) | data[50];
581 2 uint16_t height = (data[53] << 8) | data[52];
582
583 2 self->area_sensor = !(data[49] & 0x80);
584
585
2/6
✓ Branch 7 → 8 taken 1 time.
✗ Branch 7 → 14 not taken.
✗ Branch 7 → 20 not taken.
✓ Branch 7 → 26 taken 1 time.
✗ Branch 7 → 32 not taken.
✗ Branch 7 → 38 not taken.
2 switch (width)
586 {
587 1 case 256:
588 1 fp_dbg ("Sensor type : TCS1x, width x height: %hu x %hu", width, height); /* 360x256 --- 270x192 must be set */
589
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 13 taken 1 time.
1 BUG_ON (height != 360);
590 1 img_class->img_width = 192;
591 1 img_class->img_height = 270;
592 1 break;
593
594 case 208:
595 fp_dbg ("Sensor type : TCS2, width x height: %hu x %hu", width, height); /* 288x208 --- 216x156 must be set */
596 BUG_ON (height != 288);
597 img_class->img_width = 156;
598 img_class->img_height = 216;
599 break;
600
601 case 248:
602 fp_dbg ("Sensor type : TCS3, width x height: %hu x %hu", width, height); /* 360x248 --- 270x186 must be set */
603 BUG_ON (height != 360);
604 img_class->img_width = 186;
605 img_class->img_height = 270;
606 break;
607
608 1 case 192:
609 1 fp_dbg ("Sensor type : TCS4x, width x height: %hu x %hu", width, height); /* 512x192 --- 384x144 must be set */
610
1/2
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 31 taken 1 time.
1 BUG_ON (height != 512);
611 1 img_class->img_width = 144;
612 1 img_class->img_height = 384;
613 1 break;
614
615 case 144:
616 fp_dbg ("Sensor type : TCS5x, width x height: %hu x %hu", width, height); /* 512x144 --- 384x108 must be set */
617 BUG_ON (height != 512);
618 img_class->img_width = 108;
619 img_class->img_height = 384;
620 break;
621
622 default:
623 fp_dbg ("Sensor type : Unknown");
624
625 fpi_ssm_mark_failed (transfer->ssm,
626 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
627 "Unknown sensor type (reported size %dx%d)",
628 width, height));
629
630 return;
631 }
632
633 2 self->expected_image_size = img_class->img_width * img_class->img_height;
634
1/2
✗ Branch 42 → 43 not taken.
✓ Branch 42 → 44 taken 2 times.
2 g_clear_pointer (&self->image_bits, g_free);
635 2 self->image_bits = g_malloc0 (self->expected_image_size * 2);
636 }
637
638 12 fpi_ssm_next_state (transfer->ssm);
639 }
640
641 static void
642 24 activate_run_state (FpiSsm *ssm, FpDevice *dev)
643 {
644 24 FpiUsbTransfer *transfer;
645 24 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
646 24 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
647
648
6/7
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 8 taken 2 times.
✓ Branch 3 → 10 taken 2 times.
✓ Branch 3 → 12 taken 2 times.
✓ Branch 3 → 14 taken 2 times.
✓ Branch 3 → 16 taken 12 times.
✗ Branch 3 → 18 not taken.
24 switch (fpi_ssm_get_cur_state (ssm))
649 {
650 4 case ACTIVATE_CONTROL_REQ_1:
651 case ACTIVATE_CONTROL_REQ_2:
652 {
653 4 transfer = fpi_usb_transfer_new (dev);
654
655 4 fpi_usb_transfer_fill_control (transfer,
656 G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
657 G_USB_DEVICE_REQUEST_TYPE_VENDOR,
658 G_USB_DEVICE_RECIPIENT_DEVICE,
659 0x0c, 0x100, 0x0400, 1);
660 4 transfer->buffer[0] = '\0';
661 4 transfer->ssm = ssm;
662 4 fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
663 fpi_ssm_usb_transfer_cb, NULL);
664 }
665 4 break;
666
667 2 case ACTIVATE_INIT_1:
668 2 upektc_img_submit_req (ssm, idev, upek2020_init_1, sizeof (upek2020_init_1),
669 0, init_reqs_cb);
670 2 break;
671
672 2 case ACTIVATE_INIT_2:
673 2 upektc_img_submit_req (ssm, idev, upek2020_init_2, sizeof (upek2020_init_2),
674 0, init_reqs_cb);
675 2 break;
676
677 2 case ACTIVATE_INIT_3:
678 2 upektc_img_submit_req (ssm, idev, upek2020_init_3, sizeof (upek2020_init_3),
679 0, init_reqs_cb);
680 2 break;
681
682 2 case ACTIVATE_INIT_4:
683 2 upektc_img_submit_req (ssm, idev, upek2020_init_4, sizeof (upek2020_init_4),
684 self->seq, init_reqs_cb);
685 /* Seq should be updated after 4th init */
686 2 self->seq++;
687 2 break;
688
689 12 case ACTIVATE_READ_CTRL_RESP_1:
690 case ACTIVATE_READ_CTRL_RESP_2:
691 case ACTIVATE_READ_INIT_1_RESP:
692 case ACTIVATE_READ_INIT_2_RESP:
693 case ACTIVATE_READ_INIT_3_RESP:
694 case ACTIVATE_READ_INIT_4_RESP:
695 12 upektc_img_read_data (ssm, idev, SHORT_RESPONSE_SIZE, 0, init_read_data_cb);
696 12 break;
697 }
698 24 }
699
700 static void
701 2 activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
702 {
703 2 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
704
705 2 fpi_image_device_activate_complete (dev, error);
706
707
1/2
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 5 not taken.
2 if (!error)
708 2 start_capture (dev);
709 2 }
710
711 static void
712 2 dev_activate (FpImageDevice *dev)
713 {
714 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
715 2 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
716 ACTIVATE_NUM_STATES);
717
718 2 self->seq = 0;
719 2 fpi_ssm_start (ssm, activate_sm_complete);
720 2 }
721
722 static void
723 2 dev_deactivate (FpImageDevice *dev)
724 {
725 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
726
727 2 self->deactivating = TRUE;
728 2 }
729
730 static void
731 2 dev_init (FpImageDevice *dev)
732 {
733 2 GError *error = NULL;
734
735 /* TODO check that device has endpoints we're using */
736
737
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2 times.
2 if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
738 {
739 fpi_image_device_open_complete (dev, error);
740 return;
741 }
742
743 2 fpi_image_device_open_complete (dev, NULL);
744 }
745
746 static void
747 2 dev_deinit (FpImageDevice *dev)
748 {
749 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
750 2 GError *error = NULL;
751
752
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
2 g_clear_pointer (&self->image_bits, g_free);
753 2 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
754 0, 0, &error);
755 2 fpi_image_device_close_complete (dev, error);
756 2 }
757
758 static int
759 2 discover (GUsbDevice *usb_device)
760 {
761 2 gint16 pid = g_usb_device_get_pid (usb_device);
762 2 gint16 bcd = g_usb_device_get_release (usb_device);
763
764
1/2
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 7 not taken.
2 if (pid == 0x2020 && bcd == 1)
765 return 100;
766
1/2
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 7 not taken.
2 if (pid == 0x2016 && bcd == 2)
767 2 return 100;
768
769 return 0;
770 }
771
772 static const FpIdEntry id_table[] = {
773 { .vid = 0x147e, .pid = 0x2016, },
774 { .vid = 0x147e, .pid = 0x2020, },
775 { .vid = 0, .pid = 0, .driver_data = 0 },
776 };
777
778 static void
779 2 fpi_device_upektc_img_init (FpiDeviceUpektcImg *self)
780 {
781 2 }
782 static void
783 125 fpi_device_upektc_img_class_init (FpiDeviceUpektcImgClass *klass)
784 {
785 125 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
786 125 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
787
788 125 dev_class->id = "upektc_img";
789 125 dev_class->full_name = "Upek TouchChip Fingerprint Coprocessor";
790 125 dev_class->type = FP_DEVICE_TYPE_USB;
791 125 dev_class->id_table = id_table;
792 125 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
793 125 dev_class->usb_discover = discover;
794
795 125 img_class->img_open = dev_init;
796 125 img_class->img_close = dev_deinit;
797 125 img_class->activate = dev_activate;
798 125 img_class->deactivate = dev_deactivate;
799
800 125 img_class->bz3_threshold = 20;
801
802 125 img_class->img_width = -1;
803 125 img_class->img_height = -1;
804 }
805