GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/upektc_img.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 307 386 79.5%
Functions: 27 27 100.0%
Branches: 70 126 55.6%

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/5
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 120 times.
✗ Branch 4 not taken.
768 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 0 not taken.
✓ Branch 1 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 0 not taken.
✓ Branch 1 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 0 not taken.
✓ Branch 1 taken 60 times.
60 if (error)
141 {
142 fpi_ssm_mark_failed (transfer->ssm, error);
143 return;
144 }
145
1/2
✗ Branch 1 not taken.
✓ Branch 2 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, unsigned char *cmd_res)
159 {
160 54 int offset = 8;
161 54 int len = ((cmd_res[5] & 0x0f) << 8) | (cmd_res[6]);
162
163 54 len -= 1;
164
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 52 times.
54 if (cmd_res[7] == 0x2c)
165 {
166 2 len -= 10;
167 2 offset += 10;
168 }
169
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 52 times.
54 if (cmd_res[7] == 0x20)
170 2 len -= 4;
171 54 memcpy (image_buf, cmd_res + offset, len);
172
173 54 return len;
174 }
175
176 static void
177 118 capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
178 gpointer user_data, GError *error)
179 {
180 118 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_GET_CLASS (dev);
182 118 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
183 118 unsigned char *data = self->response;
184 118 FpImage *img;
185 118 size_t response_size;
186
187
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 if (error)
188 {
189 fp_dbg ("request is not completed, %s", error->message);
190 fpi_ssm_mark_failed (transfer->ssm, error);
191 return;
192 }
193
194
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 if (self->deactivating)
195 {
196 fp_dbg ("Deactivate requested");
197 fpi_ssm_mark_completed (transfer->ssm);
198 return;
199 }
200
201 118 fp_dbg ("request completed, len: %.4x", (gint) transfer->actual_length);
202
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 114 times.
118 if (transfer->actual_length == 0)
203 {
204 4 fpi_ssm_jump_to_state (transfer->ssm,
205 fpi_ssm_get_cur_state (transfer->ssm));
206 4 return;
207 }
208
209
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
114 if (fpi_ssm_get_cur_state (transfer->ssm) == CAPTURE_READ_DATA_TERM)
210 {
211 fp_dbg ("Terminating SSM");
212 fpi_ssm_mark_completed (transfer->ssm);
213 return;
214 }
215
216
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 54 times.
114 if (!self->response_rest)
217 {
218 60 response_size = ((data[5] & 0x0f) << 8) + data[6];
219 60 response_size += 9; /* 7 bytes for header, 2 for CRC */
220
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 6 times.
60 if (response_size > transfer->actual_length)
221 {
222 54 fp_dbg ("response_size is %lu, actual_length is %d",
223 (gulong) response_size, (gint) transfer->actual_length);
224 54 fp_dbg ("Waiting for rest of transfer");
225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 BUG_ON (self->response_rest);
226 54 self->response_rest = response_size - transfer->actual_length;
227 54 fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
228 54 return;
229 }
230 }
231 60 self->response_rest = 0;
232
233
2/3
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
60 switch (data[4])
234 {
235 59 case 0x00:
236
4/5
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
59 switch (data[7])
237 {
238 /* No finger */
239 5 case 0x28:
240 5 fp_dbg ("18th byte is %.2x", data[18]);
241
3/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
5 switch (data[18])
242 {
243 2 case 0x0c:
244 /* no finger */
245 2 fpi_ssm_jump_to_state (transfer->ssm,
246 CAPTURE_ACK_00_28);
247 2 break;
248
249 1 case 0x13:
250 /* finger is present keep your finger on reader */
251 1 fpi_device_report_finger_status_changes (device,
252 FP_FINGER_STATUS_NEEDED,
253 FP_FINGER_STATUS_NONE);
254 2 fpi_ssm_jump_to_state (transfer->ssm,
255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 self->area_sensor ?
256 CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
257 1 break;
258
259 2 case 0x00:
260 /* finger is present! */
261 2 fpi_device_report_finger_status_changes (device,
262 FP_FINGER_STATUS_PRESENT,
263 FP_FINGER_STATUS_NONE);
264 2 fpi_ssm_jump_to_state (transfer->ssm,
265 CAPTURE_ACK_00_28);
266 2 break;
267
268 case 0x01:
269 /* no finger! */
270 fpi_device_report_finger_status_changes (device,
271 FP_FINGER_STATUS_NONE,
272 FP_FINGER_STATUS_PRESENT);
273 fpi_ssm_jump_to_state (transfer->ssm,
274 CAPTURE_ACK_00_28);
275 break;
276
277 case 0x1e:
278 /* short scan */
279 fp_err ("short scan, aborting");
280 fpi_image_device_retry_scan (dev,
281 FP_DEVICE_RETRY_TOO_SHORT);
282 fpi_image_device_report_finger_status (dev,
283 FALSE);
284 fpi_ssm_jump_to_state (transfer->ssm,
285 self->area_sensor ?
286 CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
287 break;
288
289 case 0x1d:
290 /* too much horizontal movement */
291 fp_err ("too much horizontal movement, aborting");
292 fpi_image_device_retry_scan (dev,
293 FP_DEVICE_RETRY_CENTER_FINGER);
294 fpi_image_device_report_finger_status (dev,
295 FALSE);
296 fpi_ssm_jump_to_state (transfer->ssm,
297 self->area_sensor ?
298 CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
299 break;
300
301 default:
302 /* some error happened, cancel scan */
303 fp_err ("something bad happened, stop scan");
304 fpi_image_device_retry_scan (dev,
305 FP_DEVICE_RETRY);
306 fpi_image_device_report_finger_status (dev,
307 FALSE);
308 fpi_ssm_jump_to_state (transfer->ssm,
309 self->area_sensor ?
310 CAPTURE_ACK_00_28 : CAPTURE_ACK_00_28_TERM);
311 break;
312 }
313 break;
314
315 /* Image frame with additional info */
316 2 case 0x2c:
317 2 fpi_image_device_report_finger_status (dev,
318 TRUE);
319
320 /* Plain image frame */
321 52 case 0x24:
322 104 self->image_size +=
323 52 upektc_img_process_image_frame (self->image_bits + self->image_size,
324 data);
325 52 fpi_ssm_jump_to_state (transfer->ssm,
326 CAPTURE_ACK_FRAME);
327 52 break;
328
329 /* Last image frame */
330 2 case 0x20:
331 4 self->image_size +=
332 2 upektc_img_process_image_frame (self->image_bits + self->image_size,
333 data);
334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 BUG_ON (self->image_size != self->expected_image_size);
335 2 fp_dbg ("Image size is %lu",
336 (gulong) self->image_size);
337 2 img = fp_image_new (img_class->img_width, img_class->img_height);
338 2 img->flags |= FPI_IMAGE_PARTIAL;
339 2 memcpy (img->data, self->image_bits,
340 self->image_size);
341 2 fpi_image_device_image_captured (dev, img);
342 2 fpi_image_device_report_finger_status (dev,
343 FALSE);
344 2 fpi_ssm_mark_completed (transfer->ssm);
345 2 break;
346
347 default:
348 fp_err ("Unknown response!");
349 fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
350 break;
351 }
352 break;
353
354 1 case 0x08:
355 1 fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_ACK_08);
356 1 break;
357
358 default:
359 fp_err ("Not handled response!");
360 fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
361 }
362 }
363
364 static void
365 178 capture_run_state (FpiSsm *ssm, FpDevice *_dev)
366 {
367 178 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
368 178 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
369
370
5/6
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 118 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 52 times.
✗ Branch 6 not taken.
178 switch (fpi_ssm_get_cur_state (ssm))
371 {
372 2 case CAPTURE_INIT_CAPTURE:
373
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (self->area_sensor)
374 1 upektc_img_submit_req (ssm, dev, upek2020_init_capture_press, sizeof (upek2020_init_capture_press),
375 1 self->seq, capture_reqs_cb);
376 else
377 1 upektc_img_submit_req (ssm, dev, upek2020_init_capture, sizeof (upek2020_init_capture),
378 1 self->seq, capture_reqs_cb);
379 2 self->seq++;
380 2 break;
381
382 118 case CAPTURE_READ_DATA:
383 case CAPTURE_READ_DATA_TERM:
384
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 54 times.
118 if (!self->response_rest)
385 64 upektc_img_read_data (ssm, dev, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb);
386 else
387 54 upektc_img_read_data (ssm, dev, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE,
388 SHORT_RESPONSE_SIZE, capture_read_data_cb);
389 break;
390
391 5 case CAPTURE_ACK_00_28:
392 case CAPTURE_ACK_00_28_TERM:
393 5 upektc_img_submit_req (ssm, dev, upek2020_ack_00_28, sizeof (upek2020_ack_00_28),
394 5 self->seq, capture_reqs_cb);
395 5 self->seq++;
396 5 break;
397
398 1 case CAPTURE_ACK_08:
399 1 upektc_img_submit_req (ssm, dev, upek2020_ack_08, sizeof (upek2020_ack_08),
400 0, capture_reqs_cb);
401 1 break;
402
403 52 case CAPTURE_ACK_FRAME:
404 52 upektc_img_submit_req (ssm, dev, upek2020_ack_frame, sizeof (upek2020_ack_frame),
405 52 self->seq, capture_reqs_cb);
406 52 self->seq++;
407 52 break;
408 }
409 178 ;
410 178 }
411
412 static void
413 2 capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error_arg)
414 {
415 2 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
416 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
417
418 4 g_autoptr(GError) error = error_arg;
419
420
421 /* Note: We assume that the error is a cancellation in the deactivation case */
422
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (self->deactivating)
423 2 start_deactivation (dev);
424 else if (error)
425 fpi_image_device_session_error (dev, g_steal_pointer (&error));
426 else
427 start_capture (dev);
428 2 }
429
430 static void
431 2 start_capture (FpImageDevice *dev)
432 {
433 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
434 2 FpiSsm *ssm;
435
436 2 self->image_size = 0;
437
438 2 ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state,
439 CAPTURE_NUM_STATES);
440 2 fpi_ssm_start (ssm, capture_sm_complete);
441 2 }
442
443 /****** INITIALIZATION/DEINITIALIZATION ******/
444
445 enum deactivate_states {
446 DEACTIVATE_DEINIT,
447 DEACTIVATE_READ_DEINIT_DATA,
448 DEACTIVATE_NUM_STATES,
449 };
450
451 static void
452 2 deactivate_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device,
453 gpointer user_data, GError *error)
454 {
455
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!error)
456 2 fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
457 else
458 fpi_ssm_mark_failed (transfer->ssm, error);
459 2 }
460
461 /* TODO: process response properly */
462 static void
463 2 deactivate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
464 gpointer user_data, GError *error)
465 {
466
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!error)
467 2 fpi_ssm_mark_completed (transfer->ssm);
468 else
469 fpi_ssm_mark_failed (transfer->ssm, error);
470 2 }
471
472 static void
473 4 deactivate_run_state (FpiSsm *ssm, FpDevice *_dev)
474 {
475 4 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
476 4 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
477
478
2/3
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 switch (fpi_ssm_get_cur_state (ssm))
479 {
480 2 case DEACTIVATE_DEINIT:
481 2 upektc_img_submit_req (ssm, dev, upek2020_deinit, sizeof (upek2020_deinit),
482 2 self->seq, deactivate_reqs_cb);
483 2 self->seq++;
484 2 break;
485
486 2 case DEACTIVATE_READ_DEINIT_DATA:
487 2 upektc_img_read_data (ssm, dev, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb);
488 2 break;
489 }
490 4 ;
491 4 }
492
493 static void
494 2 deactivate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
495 {
496 2 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
497 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (_dev);
498
499 2 fp_dbg ("Deactivate completed");
500
501 2 self->deactivating = FALSE;
502 2 fpi_image_device_deactivate_complete (dev, error);
503 2 }
504
505 static void
506 2 start_deactivation (FpImageDevice *dev)
507 {
508 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
509 2 FpiSsm *ssm;
510
511 2 self->image_size = 0;
512
513 2 ssm = fpi_ssm_new (FP_DEVICE (dev), deactivate_run_state,
514 DEACTIVATE_NUM_STATES);
515 2 fpi_ssm_start (ssm, deactivate_sm_complete);
516 2 }
517
518 enum activate_states {
519 ACTIVATE_CONTROL_REQ_1,
520 ACTIVATE_READ_CTRL_RESP_1,
521 ACTIVATE_INIT_1,
522 ACTIVATE_READ_INIT_1_RESP,
523 ACTIVATE_INIT_2,
524 ACTIVATE_READ_INIT_2_RESP,
525 ACTIVATE_CONTROL_REQ_2,
526 ACTIVATE_READ_CTRL_RESP_2,
527 ACTIVATE_INIT_3,
528 ACTIVATE_READ_INIT_3_RESP,
529 ACTIVATE_INIT_4,
530 ACTIVATE_READ_INIT_4_RESP,
531 ACTIVATE_NUM_STATES,
532 };
533
534 static void
535 8 init_reqs_cb (FpiUsbTransfer *transfer, FpDevice *device,
536 gpointer user_data, GError *error)
537 {
538
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (!error)
539 8 fpi_ssm_next_state (transfer->ssm);
540 else
541 fpi_ssm_mark_failed (transfer->ssm, error);
542 8 }
543
544 static void
545 12 init_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
546 gpointer user_data, GError *error)
547 {
548 12 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
549 12 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
550 12 unsigned char *data = self->response;
551
552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (error)
553 {
554 fpi_ssm_mark_failed (transfer->ssm, error);
555 return;
556 }
557
558
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
12 if (data[12] == 0x06 && data[13] == 0x14) /* if get_info */
559 {
560
2/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_GET_CLASS (dev);
561 2 uint16_t width = (data[51] << 8) | data[50];
562 2 uint16_t height = (data[53] << 8) | data[52];
563
564 2 self->area_sensor = !(data[49] & 0x80);
565
566
2/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2 switch (width)
567 {
568 1 case 256:
569 1 fp_dbg ("Sensor type : TCS1x, width x height: %hu x %hu", width, height); /* 360x256 --- 270x192 must be set */
570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 BUG_ON (height != 360);
571 1 img_class->img_width = 192;
572 1 img_class->img_height = 270;
573 1 break;
574
575 case 208:
576 fp_dbg ("Sensor type : TCS2, width x height: %hu x %hu", width, height); /* 288x208 --- 216x156 must be set */
577 BUG_ON (height != 288);
578 img_class->img_width = 156;
579 img_class->img_height = 216;
580 break;
581
582 case 248:
583 fp_dbg ("Sensor type : TCS3, width x height: %hu x %hu", width, height); /* 360x248 --- 270x186 must be set */
584 BUG_ON (height != 360);
585 img_class->img_width = 186;
586 img_class->img_height = 270;
587 break;
588
589 1 case 192:
590 1 fp_dbg ("Sensor type : TCS4x, width x height: %hu x %hu", width, height); /* 512x192 --- 384x144 must be set */
591
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 BUG_ON (height != 512);
592 1 img_class->img_width = 144;
593 1 img_class->img_height = 384;
594 1 break;
595
596 case 144:
597 fp_dbg ("Sensor type : TCS5x, width x height: %hu x %hu", width, height); /* 512x144 --- 384x108 must be set */
598 BUG_ON (height != 512);
599 img_class->img_width = 108;
600 img_class->img_height = 384;
601 break;
602
603 default:
604 fp_dbg ("Sensor type : Unknown");
605
606 fpi_ssm_mark_failed (transfer->ssm,
607 fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
608 "Unknown sensor type (reported size %dx%d)",
609 width, height));
610
611 return;
612 }
613
614 2 self->expected_image_size = img_class->img_width * img_class->img_height;
615 2 self->image_bits = g_malloc0 (self->expected_image_size * 2);
616 }
617
618 12 fpi_ssm_next_state (transfer->ssm);
619 }
620
621 static void
622 24 activate_run_state (FpiSsm *ssm, FpDevice *dev)
623 {
624 24 FpiUsbTransfer *transfer;
625 24 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
626 24 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
627
628
6/7
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
24 switch (fpi_ssm_get_cur_state (ssm))
629 {
630 4 case ACTIVATE_CONTROL_REQ_1:
631 case ACTIVATE_CONTROL_REQ_2:
632 {
633 4 transfer = fpi_usb_transfer_new (dev);
634
635 4 fpi_usb_transfer_fill_control (transfer,
636 G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
637 G_USB_DEVICE_REQUEST_TYPE_VENDOR,
638 G_USB_DEVICE_RECIPIENT_DEVICE,
639 0x0c, 0x100, 0x0400, 1);
640 4 transfer->buffer[0] = '\0';
641 4 transfer->ssm = ssm;
642 4 fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
643 fpi_ssm_usb_transfer_cb, NULL);
644 }
645 4 break;
646
647 2 case ACTIVATE_INIT_1:
648 2 upektc_img_submit_req (ssm, idev, upek2020_init_1, sizeof (upek2020_init_1),
649 0, init_reqs_cb);
650 2 break;
651
652 2 case ACTIVATE_INIT_2:
653 2 upektc_img_submit_req (ssm, idev, upek2020_init_2, sizeof (upek2020_init_2),
654 0, init_reqs_cb);
655 2 break;
656
657 2 case ACTIVATE_INIT_3:
658 2 upektc_img_submit_req (ssm, idev, upek2020_init_3, sizeof (upek2020_init_3),
659 0, init_reqs_cb);
660 2 break;
661
662 2 case ACTIVATE_INIT_4:
663 2 upektc_img_submit_req (ssm, idev, upek2020_init_4, sizeof (upek2020_init_4),
664 2 self->seq, init_reqs_cb);
665 /* Seq should be updated after 4th init */
666 2 self->seq++;
667 2 break;
668
669 12 case ACTIVATE_READ_CTRL_RESP_1:
670 case ACTIVATE_READ_CTRL_RESP_2:
671 case ACTIVATE_READ_INIT_1_RESP:
672 case ACTIVATE_READ_INIT_2_RESP:
673 case ACTIVATE_READ_INIT_3_RESP:
674 case ACTIVATE_READ_INIT_4_RESP:
675 12 upektc_img_read_data (ssm, idev, SHORT_RESPONSE_SIZE, 0, init_read_data_cb);
676 12 break;
677 }
678 24 }
679
680 static void
681 2 activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
682 {
683 2 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
684
685 2 fpi_image_device_activate_complete (dev, error);
686
687
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!error)
688 2 start_capture (dev);
689 2 }
690
691 static void
692 2 dev_activate (FpImageDevice *dev)
693 {
694 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
695 2 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
696 ACTIVATE_NUM_STATES);
697
698 2 self->seq = 0;
699 2 fpi_ssm_start (ssm, activate_sm_complete);
700 2 }
701
702 static void
703 2 dev_deactivate (FpImageDevice *dev)
704 {
705 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
706
707 2 self->deactivating = TRUE;
708 2 }
709
710 static void
711 2 dev_init (FpImageDevice *dev)
712 {
713 2 GError *error = NULL;
714
715 /* TODO check that device has endpoints we're using */
716
717
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
718 {
719 fpi_image_device_open_complete (dev, error);
720 return;
721 }
722
723 2 fpi_image_device_open_complete (dev, NULL);
724 }
725
726 static void
727 2 dev_deinit (FpImageDevice *dev)
728 {
729 2 FpiDeviceUpektcImg *self = FPI_DEVICE_UPEKTC_IMG (dev);
730 2 GError *error = NULL;
731
732
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 g_clear_pointer (&self->image_bits, g_free);
733 2 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
734 0, 0, &error);
735 2 fpi_image_device_close_complete (dev, error);
736 2 }
737
738 static int
739 2 discover (GUsbDevice *usb_device)
740 {
741 2 gint16 pid = g_usb_device_get_pid (usb_device);
742 2 gint16 bcd = g_usb_device_get_release (usb_device);
743
744
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (pid == 0x2020 && bcd == 1)
745 return 100;
746
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (pid == 0x2016 && bcd == 2)
747 2 return 100;
748
749 return 0;
750 }
751
752 static const FpIdEntry id_table[] = {
753 { .vid = 0x147e, .pid = 0x2016, },
754 { .vid = 0x147e, .pid = 0x2020, },
755 { .vid = 0, .pid = 0, .driver_data = 0 },
756 };
757
758 static void
759 2 fpi_device_upektc_img_init (FpiDeviceUpektcImg *self)
760 {
761 2 }
762 static void
763 120 fpi_device_upektc_img_class_init (FpiDeviceUpektcImgClass *klass)
764 {
765 120 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
766 120 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
767
768 120 dev_class->id = "upektc_img";
769 120 dev_class->full_name = "Upek TouchChip Fingerprint Coprocessor";
770 120 dev_class->type = FP_DEVICE_TYPE_USB;
771 120 dev_class->id_table = id_table;
772 120 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
773 120 dev_class->usb_discover = discover;
774
775 120 img_class->img_open = dev_init;
776 120 img_class->img_close = dev_deinit;
777 120 img_class->activate = dev_activate;
778 120 img_class->deactivate = dev_deactivate;
779
780 120 img_class->bz3_threshold = 20;
781
782 120 img_class->img_width = -1;
783 120 img_class->img_height = -1;
784 }
785