GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 8.7% 18 / 0 / 208
Functions: 13.6% 3 / 0 / 22
Branches: 8.5% 4 / 0 / 47

libfprint/drivers/upektc.c
Line Branch Exec Source
1 /*
2 * UPEK TouchChip driver for libfprint
3 * Copyright (C) 2007 Jan-Michael Brummer <buzz2@gmx.de>
4 * Copyright (C) 2012 Vasily Khoruzhick <anarsoul@gmail.com>
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 "upektc"
22
23 #include "drivers_api.h"
24 #include "upektc.h"
25
26 #define UPEKTC_EP_IN (2 | FPI_USB_ENDPOINT_IN)
27 #define UPEKTC_EP_OUT (3 | FPI_USB_ENDPOINT_OUT)
28 #define UPEKET_EP_IN (1 | FPI_USB_ENDPOINT_IN)
29 #define UPEKET_EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
30 #define BULK_TIMEOUT 4000
31
32 struct _FpiDeviceUpektc
33 {
34 FpImageDevice parent;
35
36 gboolean deactivating;
37 const struct setup_cmd *setup_commands;
38 size_t setup_commands_len;
39 int ep_in;
40 int ep_out;
41 int init_idx;
42 int sum_threshold;
43 };
44 G_DECLARE_FINAL_TYPE (FpiDeviceUpektc, fpi_device_upektc, FPI, DEVICE_UPEKTC,
45 FpImageDevice);
46
4/6
fpi_device_upektc_class_intern_init:
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 128 times.
fpi_device_upektc_get_type:
✓ Branch 2 → 3 taken 128 times.
✓ Branch 2 → 7 taken 24 times.
✓ Branch 4 → 5 taken 128 times.
✗ Branch 4 → 7 not taken.
408 G_DEFINE_TYPE (FpiDeviceUpektc, fpi_device_upektc, FP_TYPE_IMAGE_DEVICE);
47
48 enum upektc_driver_data {
49 UPEKTC_2015,
50 UPEKTC_3001,
51 };
52
53 static void start_capture (FpImageDevice *dev);
54 static void complete_deactivation (FpImageDevice *dev,
55 GError *error);
56 static void start_finger_detection (FpImageDevice *dev);
57
58 /****** INITIALIZATION/DEINITIALIZATION ******/
59
60 enum activate_states {
61 WRITE_INIT,
62 READ_DATA,
63 ACTIVATE_NUM_STATES,
64 };
65
66 static void
67 ✗ upektc_next_init_cmd (FpiSsm *ssm,
68 FpImageDevice *dev)
69 {
70 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
71
72 ✗ self->init_idx += 1;
73 ✗ if (self->init_idx == self->setup_commands_len)
74 ✗ fpi_ssm_mark_completed (ssm);
75 else
76 ✗ fpi_ssm_jump_to_state (ssm, WRITE_INIT);
77 ✗ }
78
79 static void
80 ✗ write_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
81 gpointer user_data, GError *error)
82 {
83 ✗ FpImageDevice *dev = FP_IMAGE_DEVICE (device);
84 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
85
86 ✗ if (!error)
87 {
88 ✗ if (self->setup_commands[self->init_idx].response_len)
89 ✗ fpi_ssm_next_state (transfer->ssm);
90 else
91 ✗ upektc_next_init_cmd (transfer->ssm, dev);
92 }
93 else
94 {
95 ✗ fpi_ssm_mark_failed (transfer->ssm, error);
96 }
97 ✗ }
98
99 static void
100 ✗ read_init_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
101 gpointer user_data, GError *error)
102 {
103 ✗ FpImageDevice *dev = FP_IMAGE_DEVICE (device);
104
105 ✗ if (!error)
106 ✗ upektc_next_init_cmd (transfer->ssm, dev);
107 else
108 ✗ fpi_ssm_mark_failed (transfer->ssm, error);
109 ✗ }
110
111 static void
112 ✗ activate_run_state (FpiSsm *ssm, FpDevice *dev)
113 {
114 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
115
116 ✗ switch (fpi_ssm_get_cur_state (ssm))
117 {
118 ✗ case WRITE_INIT:
119 {
120 ✗ FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
121
122 ✗ fpi_usb_transfer_fill_bulk_full (transfer,
123 ✗ self->ep_out,
124 ✗ (unsigned char *) self->setup_commands[self->init_idx].cmd,
125 UPEKTC_CMD_LEN,
126 NULL);
127 ✗ transfer->ssm = ssm;
128 ✗ transfer->short_is_error = TRUE;
129 ✗ fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
130 write_init_cb, NULL);
131 }
132 ✗ break;
133
134 ✗ case READ_DATA:
135 {
136 ✗ FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
137
138 ✗ fpi_usb_transfer_fill_bulk (transfer,
139 ✗ self->ep_in,
140 ✗ self->setup_commands[self->init_idx].response_len);
141 ✗ transfer->ssm = ssm;
142 ✗ fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
143 read_init_data_cb, NULL);
144 }
145 ✗ break;
146 }
147 ✗ }
148
149 static void
150 ✗ activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
151 {
152 ✗ FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
153
154 ✗ fpi_image_device_activate_complete (dev, error);
155
156 ✗ if (!error)
157 ✗ start_finger_detection (dev);
158 ✗ }
159
160
161 /****** FINGER PRESENCE DETECTION ******/
162
163 static int
164 ✗ finger_present (unsigned char *img, size_t len, int sum_threshold)
165 {
166 ✗ int i, sum;
167
168 ✗ sum = 0;
169
170 ✗ for (i = 0; i < len; i++)
171 ✗ if (img[i] < 160)
172 ✗ sum++;
173
174 ✗ fp_dbg ("finger_present: sum is %d", sum);
175 ✗ return sum < sum_threshold ? 0 : 1;
176 }
177
178 static void
179 ✗ finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
180 gpointer user_data, GError *error)
181 {
182 ✗ FpImageDevice *dev = FP_IMAGE_DEVICE (device);
183 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
184
185 ✗ if (error)
186 {
187 ✗ fp_dbg ("data transfer status %s", error->message);
188 ✗ fpi_image_device_session_error (dev, error);
189 ✗ return;
190 }
191
192 ✗ if (finger_present (transfer->buffer, IMAGE_SIZE, self->sum_threshold))
193 {
194 /* finger present, start capturing */
195 ✗ fpi_image_device_report_finger_status (dev, TRUE);
196 ✗ start_capture (dev);
197 }
198 else
199 {
200 /* no finger, poll for a new histogram */
201 ✗ start_finger_detection (dev);
202 }
203 }
204
205 static void
206 ✗ finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device,
207 gpointer user_data, GError *error)
208 {
209 ✗ FpiUsbTransfer *transfer;
210 ✗ FpImageDevice *dev = FP_IMAGE_DEVICE (device);
211 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
212
213 ✗ if (error)
214 {
215 ✗ fp_dbg ("req transfer status %s", error->message);
216 ✗ fpi_image_device_session_error (dev, error);
217 ✗ return;
218 }
219
220 ✗ transfer = fpi_usb_transfer_new (device);
221 ✗ transfer->short_is_error = TRUE;
222 ✗ fpi_usb_transfer_fill_bulk (transfer, self->ep_in,
223 IMAGE_SIZE);
224 ✗ fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
225 finger_det_data_cb, NULL);
226 }
227
228 static void
229 ✗ start_finger_detection (FpImageDevice *dev)
230 {
231 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
232 ✗ FpiUsbTransfer *transfer;
233
234 ✗ G_DEBUG_HERE ();
235
236 ✗ if (self->deactivating)
237 {
238 ✗ complete_deactivation (dev, NULL);
239 ✗ return;
240 }
241
242 ✗ transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
243 ✗ transfer->short_is_error = TRUE;
244 ✗ fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out,
245 (unsigned char *) scan_cmd,
246 UPEKTC_CMD_LEN, NULL);
247 ✗ fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
248 finger_det_cmd_cb, NULL);
249 }
250
251 /****** CAPTURE ******/
252
253 enum capture_states {
254 CAPTURE_WRITE_CMD,
255 CAPTURE_READ_DATA,
256 CAPTURE_NUM_STATES,
257 };
258
259 static void
260 ✗ capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
261 gpointer user_data, GError *error)
262 {
263 ✗ FpImageDevice *dev = FP_IMAGE_DEVICE (device);
264 ✗ FpImage *img;
265
266 ✗ if (error)
267 {
268 ✗ fp_dbg ("request is not completed, %s", error->message);
269 ✗ fpi_ssm_mark_failed (transfer->ssm, error);
270 ✗ return;
271 }
272
273 ✗ img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
274 ✗ memcpy (img->data, transfer->buffer, IMAGE_SIZE);
275 ✗ fpi_image_device_image_captured (dev, img);
276 ✗ fpi_image_device_report_finger_status (dev, FALSE);
277 ✗ fpi_ssm_mark_completed (transfer->ssm);
278 }
279
280 static void
281 ✗ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
282 {
283 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev);
284
285 ✗ switch (fpi_ssm_get_cur_state (ssm))
286 {
287 ✗ case CAPTURE_WRITE_CMD:
288 {
289 ✗ FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
290
291 ✗ fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out,
292 (unsigned char *) scan_cmd,
293 UPEKTC_CMD_LEN, NULL);
294 ✗ transfer->ssm = ssm;
295 ✗ transfer->short_is_error = TRUE;
296 ✗ fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
297 fpi_ssm_usb_transfer_cb, NULL);
298 }
299 ✗ break;
300
301 ✗ case CAPTURE_READ_DATA:
302 {
303 ✗ FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
304
305 ✗ fpi_usb_transfer_fill_bulk (transfer, self->ep_in,
306 IMAGE_SIZE);
307 ✗ transfer->ssm = ssm;
308 ✗ transfer->short_is_error = TRUE;
309 ✗ fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
310 capture_read_data_cb, NULL);
311 }
312 ✗ break;
313 }
314 ✗ ;
315 ✗ }
316
317 static void
318 ✗ capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
319 {
320 ✗ FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
321 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev);
322
323 ✗ fp_dbg ("Capture completed");
324 ✗ if (self->deactivating)
325 ✗ complete_deactivation (dev, error);
326 ✗ else if (error)
327 ✗ fpi_image_device_session_error (dev, error);
328 else
329 ✗ start_finger_detection (dev);
330
331 ✗ }
332
333 static void
334 ✗ start_capture (FpImageDevice *dev)
335 {
336 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
337 ✗ FpiSsm *ssm;
338
339 ✗ if (self->deactivating)
340 {
341 ✗ complete_deactivation (dev, NULL);
342 ✗ return;
343 }
344
345 ✗ ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES);
346 ✗ G_DEBUG_HERE ();
347 ✗ fpi_ssm_start (ssm, capture_sm_complete);
348 }
349
350 static void
351 ✗ dev_activate (FpImageDevice *dev)
352 {
353 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
354 ✗ FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
355 ACTIVATE_NUM_STATES);
356
357 ✗ self->init_idx = 0;
358 ✗ fpi_ssm_start (ssm, activate_sm_complete);
359 ✗ }
360
361 static void
362 ✗ dev_deactivate (FpImageDevice *dev)
363 {
364 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
365
366 ✗ self->deactivating = TRUE;
367 ✗ }
368
369 static void
370 ✗ complete_deactivation (FpImageDevice *dev, GError *error)
371 {
372 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
373
374 ✗ G_DEBUG_HERE ();
375
376 ✗ self->deactivating = FALSE;
377 ✗ fpi_image_device_deactivate_complete (dev, error);
378 ✗ }
379
380 static void
381 ✗ dev_init (FpImageDevice *dev)
382 {
383 ✗ GError *error = NULL;
384 ✗ FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
385 ✗ guint64 driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
386
387 /* TODO check that device has endpoints we're using */
388
389 ✗ if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
390 {
391 ✗ fpi_image_device_open_complete (dev, error);
392 ✗ return;
393 }
394
395 ✗ switch (driver_data)
396 {
397 ✗ case UPEKTC_2015:
398 ✗ self->ep_in = UPEKTC_EP_IN;
399 ✗ self->ep_out = UPEKTC_EP_OUT;
400 ✗ self->setup_commands = upektc_setup_commands;
401 ✗ self->setup_commands_len = G_N_ELEMENTS (upektc_setup_commands);
402 ✗ self->sum_threshold = UPEKTC_SUM_THRESHOLD;
403 ✗ break;
404
405 ✗ case UPEKTC_3001:
406 ✗ self->ep_in = UPEKET_EP_IN;
407 ✗ self->ep_out = UPEKET_EP_OUT;
408 ✗ self->setup_commands = upeket_setup_commands;
409 ✗ self->setup_commands_len = G_N_ELEMENTS (upeket_setup_commands);
410 ✗ self->sum_threshold = UPEKET_SUM_THRESHOLD;
411 ✗ break;
412
413 ✗ default:
414 ✗ fp_err ("Device variant %" G_GUINT64_FORMAT " is not known", driver_data);
415 ✗ g_assert_not_reached ();
416 fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
417 return;
418 }
419 ✗ fpi_image_device_open_complete (dev, NULL);
420 }
421
422 static void
423 ✗ dev_deinit (FpImageDevice *dev)
424 {
425 ✗ GError *error = NULL;
426
427 ✗ g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
428 0, 0, &error);
429 ✗ fpi_image_device_close_complete (dev, error);
430 ✗ }
431
432 static const FpIdEntry id_table[] = {
433 { .vid = 0x0483, .pid = 0x2015, .driver_data = UPEKTC_2015 },
434 { .vid = 0x0483, .pid = 0x2017, .driver_data = UPEKTC_2015 },
435 { .vid = 0x147e, .pid = 0x3001, .driver_data = UPEKTC_3001 },
436 { .vid = 0, .pid = 0, .driver_data = 0 },
437 };
438
439 static void
440 ✗ fpi_device_upektc_init (FpiDeviceUpektc *self)
441 {
442 ✗ }
443 static void
444 128 fpi_device_upektc_class_init (FpiDeviceUpektcClass *klass)
445 {
446 128 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
447 128 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
448
449 128 dev_class->id = "upektc";
450 128 dev_class->full_name = "UPEK TouchChip/Eikon Touch 300";
451 128 dev_class->type = FP_DEVICE_TYPE_USB;
452 128 dev_class->id_table = id_table;
453 128 dev_class->scan_type = FP_SCAN_TYPE_PRESS;
454
455 128 img_class->img_open = dev_init;
456 128 img_class->img_close = dev_deinit;
457 128 img_class->activate = dev_activate;
458 128 img_class->deactivate = dev_deactivate;
459
460 128 img_class->bz3_threshold = 30;
461
462 128 img_class->img_width = IMAGE_WIDTH;
463 128 img_class->img_height = IMAGE_HEIGHT;
464 }
465